Explorar o código

Merge branch 'IxAsyncCSharp8' of https://github.com/dotnet/reactive into IxAsyncCSharp8

Bart De Smet %!s(int64=6) %!d(string=hai) anos
pai
achega
4248578ed8

+ 3 - 0
Ix.NET/Source/Directory.build.targets

@@ -10,6 +10,9 @@
   <PropertyGroup Condition="'$(TargetFramework)' == 'net45'">
     <DefineConstants>$(DefineConstants);NO_ARRAY_EMPTY;NO_TASK_FROMEXCEPTION</DefineConstants>
   </PropertyGroup>
+  <PropertyGroup Condition="'$(TargetFramework)' == 'net46'">
+    <DefineConstants>$(DefineConstants);USE_ASYNC_ITERATOR</DefineConstants>
+  </PropertyGroup>
   <PropertyGroup Condition="'$(TargetFramework)' == 'netcoreapp3.0' or '$(TargetFramework)' == 'netstandard2.1'">
     <!--
     NB: USE_ASYNC_ITERATOR relies on members in the framework only present in .NET Core 3.0 Preview 2 at the moment:

+ 0 - 117
Ix.NET/Source/System.Interactive.Async.Providers/Reflection.cs

@@ -1,117 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the Apache 2.0 License.
-// See the LICENSE file in the project root for more information. 
-
-#if CRIPPLED_REFLECTION
-
-using System.Linq;
-using System.Reflection;
-
-namespace System.Reflection
-{
-    [Flags]
-    internal enum BindingFlags
-    {
-        Instance = 4,
-        Static = 8,
-        Public = 16,
-        NonPublic = 32,
-    }
-}
-
-namespace System
-{
-    internal static class TypeExtensions
-    {
-        public static bool IsNestedPrivate(this Type t)
-        {
-            return t.GetTypeInfo().IsNestedPrivate;
-        }
-
-        public static bool IsInterface(this Type t)
-        {
-            return t.GetTypeInfo().IsInterface;
-        }
-
-        public static bool IsGenericType(this Type t)
-        {
-            return t.GetTypeInfo().IsGenericType;
-        }
-
-        public static Type GetBaseType(this Type t)
-        {
-            return t.GetTypeInfo().BaseType;
-        }
-
-        public static Type[] GetGenericArguments(this Type t)
-        {
-            // TODO: check what's the right way to support this
-            return t.GetTypeInfo().GenericTypeParameters.ToArray();
-        }
-
-        public static Type[] GetInterfaces(this Type t)
-        {
-            return t.GetTypeInfo().ImplementedInterfaces.ToArray();
-        }
-
-        public static bool IsAssignableFrom(this Type t1, Type t2)
-        {
-            return t1.GetTypeInfo().IsAssignableFrom(t2.GetTypeInfo());
-        }
-
-        public static MethodInfo[] GetMethods(this Type t, BindingFlags flags)
-        {
-            return t.GetTypeInfo().DeclaredMethods.Where(m => IsVisible(m, flags)).ToArray();
-        }
-
-        private static bool IsVisible(MethodInfo method, BindingFlags flags)
-        {
-            if ((flags & BindingFlags.Public) != 0 != method.IsPublic)
-            {
-                return false;
-            }
-
-            if ((flags & BindingFlags.NonPublic) == 0 && !method.IsPublic)
-            {
-                return false;
-            }
-
-            if ((flags & BindingFlags.Static) != 0 != method.IsStatic)
-            {
-                return false;
-            }
-
-            return true;
-        }
-    }
-}
-
-#else
-
-namespace System
-{
-    internal static class TypeExtensions
-    {
-        public static bool IsNestedPrivate(this Type t)
-        {
-            return t.IsNestedPrivate;
-        }
-
-        public static bool IsInterface(this Type t)
-        {
-            return t.IsInterface;
-        }
-
-        public static bool IsGenericType(this Type t)
-        {
-            return t.IsGenericType;
-        }
-
-        public static Type GetBaseType(this Type t)
-        {
-            return t.BaseType;
-        }
-    }
-}
-
-#endif

+ 1 - 5
Ix.NET/Source/System.Interactive.Async.Providers/System.Interactive.Async.Providers.csproj

@@ -3,7 +3,7 @@
   <PropertyGroup>
     <Description>Interactive Extensions Async Providers Library used to build query providers and express queries over async enumerable sequences.</Description>
     <AssemblyTitle>Interactive Extensions - Async Providers Library</AssemblyTitle>
-    <TargetFrameworks>net45;net46;netstandard1.4;netstandard2.0;netcoreapp3.0</TargetFrameworks>
+    <TargetFrameworks>net45;net46;netstandard2.0;netcoreapp3.0</TargetFrameworks>
     <PackageTags>Ix;Interactive;Extensions;Enumerable;Asynchronous</PackageTags>
   </PropertyGroup>
 
@@ -16,10 +16,6 @@
     <ProjectReference Include="..\System.Linq.Async.Queryable\System.Linq.Async.Queryable.csproj" />
   </ItemGroup>
 
-  <ItemGroup Condition="'$(TargetFramework)' == 'netstandard1.0'">
-    <PackageReference Include="System.Linq.Queryable" Version="4.3.0" />
-  </ItemGroup>
-
   <ItemGroup>
     <None Update="System\Linq\AsyncQueryableEx.Generated.tt" Generator="TextTemplatingFileGenerator" LastGenOutput="AsyncQueryableEx.Generated.cs" />
     <Compile Update="System\Linq\AsyncQueryableEx.Generated.cs" DesignTime="True" AutoGen="True" DependentUpon="AsyncQueryableEx.Generated.tt" />

+ 1 - 1
Ix.NET/Source/System.Interactive.Async/System.Interactive.Async.csproj

@@ -3,7 +3,7 @@
   <PropertyGroup>
     <Description>Interactive Extensions Async Library used to express queries over asynchronous enumerable sequences.</Description>
     <AssemblyTitle>Interactive Extensions - Async Library</AssemblyTitle>
-    <TargetFrameworks>net45;net46;netstandard1.4;netstandard2.0;netcoreapp3.0</TargetFrameworks>
+    <TargetFrameworks>net45;net46;netstandard2.0;netcoreapp3.0</TargetFrameworks>
     <PackageTags>Ix;Interactive;Extensions;Enumerable;Asynchronous</PackageTags>
   </PropertyGroup>
 

+ 0 - 117
Ix.NET/Source/System.Linq.Async.Queryable/Reflection.cs

@@ -1,117 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the Apache 2.0 License.
-// See the LICENSE file in the project root for more information. 
-
-#if CRIPPLED_REFLECTION
-
-using System.Linq;
-using System.Reflection;
-
-namespace System.Reflection
-{
-    [Flags]
-    internal enum BindingFlags
-    {
-        Instance = 4,
-        Static = 8,
-        Public = 16,
-        NonPublic = 32,
-    }
-}
-
-namespace System
-{
-    internal static class TypeExtensions
-    {
-        public static bool IsNestedPrivate(this Type t)
-        {
-            return t.GetTypeInfo().IsNestedPrivate;
-        }
-
-        public static bool IsInterface(this Type t)
-        {
-            return t.GetTypeInfo().IsInterface;
-        }
-
-        public static bool IsGenericType(this Type t)
-        {
-            return t.GetTypeInfo().IsGenericType;
-        }
-
-        public static Type GetBaseType(this Type t)
-        {
-            return t.GetTypeInfo().BaseType;
-        }
-
-        public static Type[] GetGenericArguments(this Type t)
-        {
-            // TODO: check what's the right way to support this
-            return t.GetTypeInfo().GenericTypeParameters.ToArray();
-        }
-
-        public static Type[] GetInterfaces(this Type t)
-        {
-            return t.GetTypeInfo().ImplementedInterfaces.ToArray();
-        }
-
-        public static bool IsAssignableFrom(this Type t1, Type t2)
-        {
-            return t1.GetTypeInfo().IsAssignableFrom(t2.GetTypeInfo());
-        }
-
-        public static MethodInfo[] GetMethods(this Type t, BindingFlags flags)
-        {
-            return t.GetTypeInfo().DeclaredMethods.Where(m => IsVisible(m, flags)).ToArray();
-        }
-
-        private static bool IsVisible(MethodInfo method, BindingFlags flags)
-        {
-            if ((flags & BindingFlags.Public) != 0 != method.IsPublic)
-            {
-                return false;
-            }
-
-            if ((flags & BindingFlags.NonPublic) == 0 && !method.IsPublic)
-            {
-                return false;
-            }
-
-            if ((flags & BindingFlags.Static) != 0 != method.IsStatic)
-            {
-                return false;
-            }
-
-            return true;
-        }
-    }
-}
-
-#else
-
-namespace System
-{
-    internal static class TypeExtensions
-    {
-        public static bool IsNestedPrivate(this Type t)
-        {
-            return t.IsNestedPrivate;
-        }
-
-        public static bool IsInterface(this Type t)
-        {
-            return t.IsInterface;
-        }
-
-        public static bool IsGenericType(this Type t)
-        {
-            return t.IsGenericType;
-        }
-
-        public static Type GetBaseType(this Type t)
-        {
-            return t.BaseType;
-        }
-    }
-}
-
-#endif

+ 1 - 1
Ix.NET/Source/System.Linq.Async.Queryable/System.Linq.Async.Queryable.csproj

@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
   <PropertyGroup>
-    <TargetFrameworks>net45;net46;netstandard1.4;netstandard2.0;netcoreapp3.0</TargetFrameworks>
+    <TargetFrameworks>net45;net46;netstandard2.0;netcoreapp3.0</TargetFrameworks>
   </PropertyGroup>
 
   <ItemGroup>

+ 1 - 0
Ix.NET/Source/System.Linq.Async.Queryable/System/Linq/AsyncEnumerableQuery.cs

@@ -4,6 +4,7 @@
 
 using System.Collections.Generic;
 using System.Linq.Expressions;
+using System.Reflection;
 using System.Threading;
 using System.Threading.Tasks;
 

+ 5 - 5
Ix.NET/Source/System.Linq.Async.Queryable/System/Linq/AsyncEnumerableRewriter.cs

@@ -110,14 +110,14 @@ namespace System.Linq
 
         private static Type GetPublicType(Type type)
         {
-            if (!type.IsNestedPrivate())
+            if (!type.GetTypeInfo().IsNestedPrivate)
             {
                 return type;
             }
 
             foreach (var ifType in type.GetInterfaces())
             {
-                if (ifType.IsGenericType())
+                if (ifType.GetTypeInfo().IsGenericType)
                 {
                     var def = ifType.GetGenericTypeDefinition();
                     if (def == typeof(IAsyncEnumerable<>) || def == typeof(IAsyncGrouping<,>))
@@ -461,7 +461,7 @@ namespace System.Linq
                 //
                 // If the current type matches the specified definition, return.
                 //
-                if (type.IsGenericType() && type.GetGenericTypeDefinition() == definition)
+                if (type.GetTypeInfo().IsGenericType && type.GetGenericTypeDefinition() == definition)
                 {
                     return type;
                 }
@@ -469,7 +469,7 @@ namespace System.Linq
                 //
                 // Probe all interfaces implemented by the current type.
                 //
-                if (definition.IsInterface())
+                if (definition.GetTypeInfo().IsInterface)
                 {
                     foreach (var ifType in type.GetInterfaces())
                     {
@@ -484,7 +484,7 @@ namespace System.Linq
                 //
                 // Continue up the type hierarchy.
                 //
-                type = type.GetBaseType();
+                type = type.GetTypeInfo().BaseType;
             }
 
             return null;

+ 2 - 2
Ix.NET/Source/System.Linq.Async/System.Linq.Async.csproj

@@ -1,7 +1,7 @@
 <Project Sdk="MSBuild.Sdk.Extras">
 
   <PropertyGroup>
-    <TargetFrameworks>net45;net46;netstandard1.4;netstandard2.0;netcoreapp3.0</TargetFrameworks>
+    <TargetFrameworks>net45;net46;netstandard2.0;netcoreapp3.0</TargetFrameworks>
   </PropertyGroup>
 
   <ItemGroup>
@@ -18,7 +18,7 @@
   </ItemGroup>
 
   <ItemGroup>
-    <PackageReference Include="System.Threading.Tasks.Extensions" Version="4.5.2" />
+    <PackageReference Condition="'$(TargetFramework)' != 'netcoreapp3.0' " Include="System.Threading.Tasks.Extensions" Version="4.5.2" />
     <ReferenceAssemblyProjectReference Include="..\refs\System.Linq.Async.Ref\System.Linq.Async.Ref.csproj" />
   </ItemGroup>
 

+ 16 - 0
Ix.NET/Source/System.Linq.Async/System/Diagnostics/StackTraceHiddenAttribute.cs

@@ -0,0 +1,16 @@
+#if !BCL_HAS_CONFIGUREAWAIT
+
+using System;
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.Diagnostics
+{
+    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Struct, Inherited = false)]
+    internal sealed class StackTraceHiddenAttribute : Attribute
+    {
+        public StackTraceHiddenAttribute() { }
+    }
+}
+#endif

+ 95 - 0
Ix.NET/Source/System.Linq.Async/System/Runtime/CompilerServices/AsyncIteratorMethodBuilder.cs

@@ -0,0 +1,95 @@
+#if !BCL_HAS_CONFIGUREAWAIT
+
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace System.Runtime.CompilerServices
+{
+    /// <summary>Represents a builder for asynchronous iterators.</summary>
+    [StructLayout(LayoutKind.Auto)]
+    public struct AsyncIteratorMethodBuilder
+    {
+        // AsyncIteratorMethodBuilder is used by the language compiler as part of generating
+        // async iterators. For now, the implementation just wraps AsyncTaskMethodBuilder, as
+        // most of the logic is shared.  However, in the future this could be changed and
+        // optimized.  For example, we do need to allocate an object (once) to flow state like
+        // ExecutionContext, which AsyncTaskMethodBuilder handles, but it handles it by
+        // allocating a Task-derived object.  We could optimize this further by removing
+        // the Task from the hierarchy, but in doing so we'd also lose a variety of optimizations
+        // related to it, so we'd need to replicate all of those optimizations (e.g. storing
+        // that box object directly into a Task's continuation field).
+
+#pragma warning disable IDE0044 // Add readonly modifier
+        private AsyncTaskMethodBuilder _methodBuilder; // mutable struct; do not make it readonly
+#pragma warning restore IDE0044 // Add readonly modifier
+
+        /// <summary>Creates an instance of the <see cref="AsyncIteratorMethodBuilder"/> struct.</summary>
+        /// <returns>The initialized instance.</returns>
+        public static AsyncIteratorMethodBuilder Create() =>
+#if PROJECTN
+            // ProjectN's AsyncTaskMethodBuilder.Create() currently does additional debugger-related
+            // work, so we need to delegate to it.
+            new AsyncIteratorMethodBuilder() { _methodBuilder = AsyncTaskMethodBuilder.Create() };
+#else
+            // _methodBuilder should be initialized to AsyncTaskMethodBuilder.Create(), but on coreclr
+            // that Create() is a nop, so we can just return the default here.
+            default;
+#endif
+
+        /// <summary>Invokes <see cref="IAsyncStateMachine.MoveNext"/> on the state machine while guarding the <see cref="ExecutionContext"/>.</summary>
+        /// <typeparam name="TStateMachine">The type of the state machine.</typeparam>
+        /// <param name="stateMachine">The state machine instance, passed by reference.</param>
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public void MoveNext<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine =>
+#if CORERT || !BCL_HAS_CONFIGUREAWAIT
+            _methodBuilder.Start(ref stateMachine);
+#else
+            AsyncMethodBuilderCore.Start(ref stateMachine);
+#endif
+
+        /// <summary>Schedules the state machine to proceed to the next action when the specified awaiter completes.</summary>
+        /// <typeparam name="TAwaiter">The type of the awaiter.</typeparam>
+        /// <typeparam name="TStateMachine">The type of the state machine.</typeparam>
+        /// <param name="awaiter">The awaiter.</param>
+        /// <param name="stateMachine">The state machine.</param>
+        public void AwaitOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine)
+            where TAwaiter : INotifyCompletion
+            where TStateMachine : IAsyncStateMachine =>
+            _methodBuilder.AwaitOnCompleted(ref awaiter, ref stateMachine);
+
+        /// <summary>Schedules the state machine to proceed to the next action when the specified awaiter completes.</summary>
+        /// <typeparam name="TAwaiter">The type of the awaiter.</typeparam>
+        /// <typeparam name="TStateMachine">The type of the state machine.</typeparam>
+        /// <param name="awaiter">The awaiter.</param>
+        /// <param name="stateMachine">The state machine.</param>
+        public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine)
+            where TAwaiter : ICriticalNotifyCompletion
+            where TStateMachine : IAsyncStateMachine =>
+            _methodBuilder.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine);
+
+        /// <summary>Marks iteration as being completed, whether successfully or otherwise.</summary>
+        public void Complete() => _methodBuilder.SetResult();
+
+        /// <summary>Gets an object that may be used to uniquely identify this builder to the debugger.</summary>
+        internal object ObjectIdForDebugger =>  typeof(AsyncTaskMethodBuilder)
+            .GetProperty("ObjectIdForDebugger", BindingFlags.Instance | BindingFlags.NonPublic)
+            .GetMethod.Invoke(_methodBuilder, null);
+
+
+    }
+}
+
+#else
+using System.Runtime.CompilerServices;
+
+[assembly: TypeForwardedTo(typeof(AsyncIteratorMethodBuilder))]
+
+#endif

+ 1 - 1
Ix.NET/Source/System.Linq.Async/System/Runtime/CompilerServices/ConfiguredAsyncDisposable.cs

@@ -1,4 +1,4 @@
-#if !BCL_HAS_CONFIGUREAWAIT
+#if !HAS_ASYNCDISPOSABLE
 // Licensed to the .NET Foundation under one or more agreements.
 // The .NET Foundation licenses this file to you under the MIT license.
 // See the LICENSE file in the project root for more information.

+ 292 - 0
Ix.NET/Source/System.Linq.Async/System/Threading/Tasks/Sources/ManualResetValueTaskSourceCore.cs

@@ -0,0 +1,292 @@
+#if !BCL_HAS_CONFIGUREAWAIT
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics;
+using System.Runtime.ExceptionServices;
+using System.Runtime.InteropServices;
+
+namespace System.Threading.Tasks.Sources
+{
+    /// <summary>Provides the core logic for implementing a manual-reset <see cref="IValueTaskSource"/> or <see cref="IValueTaskSource{TResult}"/>.</summary>
+    /// <typeparam name="TResult"></typeparam>
+    [StructLayout(LayoutKind.Auto)]
+    public struct ManualResetValueTaskSourceCore<TResult>
+    {
+        /// <summary>
+        /// The callback to invoke when the operation completes if <see cref="OnCompleted"/> was called before the operation completed,
+        /// or <see cref="ManualResetValueTaskSourceCoreShared.s_sentinel"/> 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.
+        /// </summary>
+        private Action<object> _continuation;
+        /// <summary>State to pass to <see cref="_continuation"/>.</summary>
+        private object _continuationState;
+        /// <summary><see cref="ExecutionContext"/> to flow to the callback, or null if no flowing is required.</summary>
+        private ExecutionContext _executionContext;
+        /// <summary>
+        /// A "captured" <see cref="SynchronizationContext"/> or <see cref="TaskScheduler"/> with which to invoke the callback,
+        /// or null if no special context is required.
+        /// </summary>
+        private object _capturedContext;
+        /// <summary>Whether the current operation has completed.</summary>
+        private bool _completed;
+        /// <summary>The result with which the operation succeeded, or the default value if it hasn't yet completed or failed.</summary>
+        private TResult _result;
+        /// <summary>The exception with which the operation failed, or null if it hasn't yet completed or completed successfully.</summary>
+        private ExceptionDispatchInfo _error;
+        /// <summary>The current version of this value, used to help prevent misuse.</summary>
+        private short _version;
+
+        /// <summary>Gets or sets whether to force continuations to run asynchronously.</summary>
+        /// <remarks>Continuations may run asynchronously if this is false, but they'll never run synchronously if this is true.</remarks>
+        public bool RunContinuationsAsynchronously { get; set; }
+
+        /// <summary>Resets to prepare for the next operation.</summary>
+        public void Reset()
+        {
+            // Reset/update state for the next use/await of this instance.
+            _version++;
+            _completed = false;
+            _result = default;
+            _error = null;
+            _executionContext = null;
+            _capturedContext = null;
+            _continuation = null;
+            _continuationState = null;
+        }
+
+        /// <summary>Completes with a successful result.</summary>
+        /// <param name="result">The result.</param>
+        public void SetResult(TResult result)
+        {
+            _result = result;
+            SignalCompletion();
+        }
+
+        /// <summary>Complets with an error.</summary>
+        /// <param name="error"></param>
+        public void SetException(Exception error)
+        {
+            _error = ExceptionDispatchInfo.Capture(error);
+            SignalCompletion();
+        }
+
+        /// <summary>Gets the operation version.</summary>
+        public short Version => _version;
+
+        /// <summary>Gets the status of the operation.</summary>
+        /// <param name="token">Opaque value that was provided to the <see cref="ValueTask"/>'s constructor.</param>
+        public ValueTaskSourceStatus GetStatus(short token)
+        {
+            ValidateToken(token);
+            return
+                !_completed ? ValueTaskSourceStatus.Pending :
+                _error == null ? ValueTaskSourceStatus.Succeeded :
+                _error.SourceException is OperationCanceledException ? ValueTaskSourceStatus.Canceled :
+                ValueTaskSourceStatus.Faulted;
+        }
+
+        /// <summary>Gets the result of the operation.</summary>
+        /// <param name="token">Opaque value that was provided to the <see cref="ValueTask"/>'s constructor.</param>
+        [StackTraceHidden]
+        public TResult GetResult(short token)
+        {
+            ValidateToken(token);
+            if (!_completed)
+            {
+                ManualResetValueTaskSourceCoreShared.ThrowInvalidOperationException();
+            }
+
+            _error?.Throw();
+            return _result;
+        }
+
+        /// <summary>Schedules the continuation action for this operation.</summary>
+        /// <param name="continuation">The continuation to invoke when the operation has completed.</param>
+        /// <param name="state">The state object to pass to <paramref name="continuation"/> when it's invoked.</param>
+        /// <param name="token">Opaque value that was provided to the <see cref="ValueTask"/>'s constructor.</param>
+        /// <param name="flags">The flags describing the behavior of the continuation.</param>
+        public void OnCompleted(Action<object> continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags)
+        {
+            if (continuation == null)
+            {
+                throw new ArgumentNullException(nameof(continuation));
+            }
+            ValidateToken(token);
+
+            if ((flags & ValueTaskSourceOnCompletedFlags.FlowExecutionContext) != 0)
+            {
+                _executionContext = ExecutionContext.Capture();
+            }
+
+            if ((flags & ValueTaskSourceOnCompletedFlags.UseSchedulingContext) != 0)
+            {
+                SynchronizationContext sc = SynchronizationContext.Current;
+                if (sc != null && sc.GetType() != typeof(SynchronizationContext))
+                {
+                    _capturedContext = sc;
+                }
+                else
+                {
+                    TaskScheduler ts = TaskScheduler.Current;
+                    if (ts != TaskScheduler.Default)
+                    {
+                        _capturedContext = ts;
+                    }
+                }
+            }
+
+            // We need to set the continuation state before we swap in the delegate, so that
+            // if there's a race between this and SetResult/Exception and SetResult/Exception
+            // sees the _continuation as non-null, it'll be able to invoke it with the state
+            // stored here.  However, this also means that if this is used incorrectly (e.g.
+            // awaited twice concurrently), _continuationState might get erroneously overwritten.
+            // To minimize the chances of that, we check preemptively whether _continuation
+            // is already set to something other than the completion sentinel.
+
+            object oldContinuation = _continuation;
+            if (oldContinuation == null)
+            {
+                _continuationState = state;
+                oldContinuation = Interlocked.CompareExchange(ref _continuation, continuation, null);
+            }
+
+            if (oldContinuation != null)
+            {
+                // Operation already completed, so we need to queue the supplied callback.
+                if (!ReferenceEquals(oldContinuation, ManualResetValueTaskSourceCoreShared.s_sentinel))
+                {
+                    ManualResetValueTaskSourceCoreShared.ThrowInvalidOperationException();
+                }
+
+                switch (_capturedContext)
+                {
+                    case null:
+                        if (_executionContext != null)
+                        {
+                            ThreadPool.QueueUserWorkItem(s => continuation(s), state);
+                        }
+                        else
+                        {
+                            ThreadPool.UnsafeQueueUserWorkItem(s => continuation(s), state);
+                        }
+                        break;
+
+                    case SynchronizationContext sc:
+                        sc.Post(s =>
+                        {
+                            var tuple = (Tuple<Action<object>, object>)s;
+                            tuple.Item1(tuple.Item2);
+                        }, Tuple.Create(continuation, state));
+                        break;
+
+                    case TaskScheduler ts:
+                        Task.Factory.StartNew(continuation, state, CancellationToken.None, TaskCreationOptions.DenyChildAttach, ts);
+                        break;
+                }
+            }
+        }
+
+        /// <summary>Ensures that the specified token matches the current version.</summary>
+        /// <param name="token">The token supplied by <see cref="ValueTask"/>.</param>
+        private void ValidateToken(short token)
+        {
+            if (token != _version)
+            {
+                ManualResetValueTaskSourceCoreShared.ThrowInvalidOperationException();
+            }
+        }
+
+        /// <summary>Signals that that the operation has completed.  Invoked after the result or error has been set.</summary>
+        private void SignalCompletion()
+        {
+            if (_completed)
+            {
+                ManualResetValueTaskSourceCoreShared.ThrowInvalidOperationException();
+            }
+            _completed = true;
+
+            if (_continuation != null || Interlocked.CompareExchange(ref _continuation, ManualResetValueTaskSourceCoreShared.s_sentinel, null) != null)
+            {
+                if (_executionContext != null)
+                {
+                    ExecutionContext.Run(_executionContext,
+                        s => ((ManualResetValueTaskSourceCore<TResult>)s).InvokeContinuation(),
+                        this);
+
+                    //ExecutionContext.RunInternal(
+                    //    _executionContext,
+                    //    (ref ManualResetValueTaskSourceCore<TResult> s) => s.InvokeContinuation(),
+                    //    ref this);
+                }
+                else
+                {
+                    InvokeContinuation();
+                }
+            }
+        }
+
+        /// <summary>
+        /// Invokes the continuation with the appropriate captured context / scheduler.
+        /// This assumes that if <see cref="_executionContext"/> is not null we're already
+        /// running within that <see cref="ExecutionContext"/>.
+        /// </summary>
+        private void InvokeContinuation()
+        {
+            switch (_capturedContext)
+            {
+                case null:
+                    if (RunContinuationsAsynchronously)
+                    {
+                        var c = _continuation;
+                        if (_executionContext != null)
+                        {
+                            ThreadPool.QueueUserWorkItem(s => c(s), _continuationState);
+                        }
+                        else
+                        {
+                            ThreadPool.UnsafeQueueUserWorkItem(s => c(s), _continuationState);
+                        }
+                    }
+                    else
+                    {
+                        _continuation(_continuationState);
+                    }
+                    break;
+
+                case SynchronizationContext sc:
+                    sc.Post(s =>
+                    {
+                        var state = (Tuple<Action<object>, object>)s;
+                        state.Item1(state.Item2);
+                    }, Tuple.Create(_continuation, _continuationState));
+                    break;
+
+                case TaskScheduler ts:
+                    Task.Factory.StartNew(_continuation, _continuationState, CancellationToken.None, TaskCreationOptions.DenyChildAttach, ts);
+                    break;
+            }
+        }
+    }
+
+    internal static class ManualResetValueTaskSourceCoreShared // separated out of generic to avoid unnecessary duplication
+    {
+        [StackTraceHidden]
+        internal static void ThrowInvalidOperationException() => throw new InvalidOperationException();
+
+        internal static readonly Action<object> s_sentinel = CompletionSentinel;
+        private static void CompletionSentinel(object _) // named method to aid debugging
+        {
+            Debug.Fail("The sentinel delegate should never be invoked.");
+            ThrowInvalidOperationException();
+        }
+    }
+}
+
+#else
+
+using System.Runtime.CompilerServices;
+
+[assembly: TypeForwardedTo(typeof(System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore<>))]
+#endif

+ 3 - 2
Ix.NET/Source/refs/System.Linq.Async.Ref/System.Linq.Async.Ref.csproj

@@ -4,12 +4,13 @@
     <Description>LINQ Standard Query Operators used to express queries over asynchronous enumerable sequences.</Description>
     <AssemblyTitle>System.Linq.Async</AssemblyTitle>
     <Authors>Microsoft</Authors>
-    <TargetFrameworks>net45;netstandard1.4;netcoreapp3.0</TargetFrameworks>
+    <TargetFrameworks>net45;netstandard2.0;netcoreapp3.0</TargetFrameworks>
     <PackageTags>Enumerable;Asynchronous;LINQ</PackageTags>
   </PropertyGroup>
 
   <ItemGroup>
-    <PackageReference Include="System.Threading.Tasks.Extensions" Version="4.5.2" />
+    <PackageReference Condition="'$(TargetFramework)' != 'netcoreapp3.0' "
+                      Include="System.Threading.Tasks.Extensions" Version="4.5.2" />
   </ItemGroup>
 
   <ItemGroup>

+ 9 - 3
azure-pipelines.ix.yml

@@ -81,9 +81,15 @@ steps:
     summaryFileLocation: '$(Build.SourcesDirectory)/Ix.NET/Source/coverlet/reports/Cobertura.xml'
     reportDirectory: '$(Build.SourcesDirectory)/Ix.NET/Source/coverlet/reports'
 
-- script: |
-    choco install codecov
-    codecov -f $(Build.SourcesDirectory)/Ix.NET/Source/coverlet/reports/Cobertura.xml --flag ixnet
+- task: DotNetCoreCLI@2  
+  inputs:
+    command: custom
+    custom: tool
+    arguments: install --tool-path . Codecov.Tool
+  displayName: Install Codecov tool
+  condition: and(succeeded(), not(eq(variables['CODECOV_TOKEN'], '')))
+
+- script: codecov -f $(Build.SourcesDirectory)/Ix.NET/Source/coverlet/reports/Cobertura.xml --flag ixnet
   env:
     CODECOV_TOKEN: $(CODECOV_TOKEN)
   displayName: Upload coverage to Codecov