Browse Source

Smaller async state machines with default(T) == null check hoisted out (better JIT)

Bart De Smet 7 years ago
parent
commit
02f43e94f7

+ 212 - 152
Ix.NET/Source/System.Linq.Async/System/Linq/Operators/Max.Generic.cs

@@ -10,265 +10,325 @@ namespace System.Linq
 {
     public static partial class AsyncEnumerable
     {
-        private static async Task<TSource> MaxCore<TSource>(IAsyncEnumerable<TSource> source, CancellationToken cancellationToken)
+        private static Task<TSource> MaxCore<TSource>(IAsyncEnumerable<TSource> source, CancellationToken cancellationToken)
         {
             var comparer = Comparer<TSource>.Default;
-            var value = default(TSource);
-            if (value == null)
+            if (default(TSource) == null)
             {
-                var e = source.GetAsyncEnumerator(cancellationToken);
+                return Core();
 
-                try
+                async Task<TSource> Core()
                 {
-                    do
+                    var value = default(TSource);
+
+                    var e = source.GetAsyncEnumerator(cancellationToken);
+
+                    try
                     {
-                        if (!await e.MoveNextAsync().ConfigureAwait(false))
+                        do
                         {
-                            return value;
-                        }
+                            if (!await e.MoveNextAsync().ConfigureAwait(false))
+                            {
+                                return value;
+                            }
 
-                        value = e.Current;
-                    }
-                    while (value == null);
+                            value = e.Current;
+                        }
+                        while (value == null);
 
-                    while (await e.MoveNextAsync().ConfigureAwait(false))
-                    {
-                        var x = e.Current;
-                        if (x != null && comparer.Compare(x, value) > 0)
+                        while (await e.MoveNextAsync().ConfigureAwait(false))
                         {
-                            value = x;
+                            var x = e.Current;
+                            if (x != null && comparer.Compare(x, value) > 0)
+                            {
+                                value = x;
+                            }
                         }
                     }
-                }
-                finally
-                {
-                    await e.DisposeAsync().ConfigureAwait(false);
+                    finally
+                    {
+                        await e.DisposeAsync().ConfigureAwait(false);
+                    }
+
+                    return value;
                 }
             }
             else
             {
-                var e = source.GetAsyncEnumerator(cancellationToken);
+                return Core();
 
-                try
+                async Task<TSource> Core()
                 {
-                    if (!await e.MoveNextAsync().ConfigureAwait(false))
-                    {
-                        throw Error.NoElements();
-                    }
+                    var value = default(TSource);
+
+                    var e = source.GetAsyncEnumerator(cancellationToken);
 
-                    value = e.Current;
-                    while (await e.MoveNextAsync().ConfigureAwait(false))
+                    try
                     {
-                        var x = e.Current;
-                        if (comparer.Compare(x, value) > 0)
+                        if (!await e.MoveNextAsync().ConfigureAwait(false))
+                        {
+                            throw Error.NoElements();
+                        }
+
+                        value = e.Current;
+                        while (await e.MoveNextAsync().ConfigureAwait(false))
                         {
-                            value = x;
+                            var x = e.Current;
+                            if (comparer.Compare(x, value) > 0)
+                            {
+                                value = x;
+                            }
                         }
                     }
-                }
-                finally
-                {
-                    await e.DisposeAsync().ConfigureAwait(false);
+                    finally
+                    {
+                        await e.DisposeAsync().ConfigureAwait(false);
+                    }
+
+                    return value;
                 }
             }
-
-            return value;
         }
 
-        private static async Task<TResult> MaxCore<TSource, TResult>(IAsyncEnumerable<TSource> source, Func<TSource, TResult> selector, CancellationToken cancellationToken)
+        private static Task<TResult> MaxCore<TSource, TResult>(IAsyncEnumerable<TSource> source, Func<TSource, TResult> selector, CancellationToken cancellationToken)
         {
             var comparer = Comparer<TResult>.Default;
-            var value = default(TResult);
-            if (value == null)
+            if (default(TResult) == null)
             {
-                var e = source.GetAsyncEnumerator(cancellationToken);
+                return Core();
 
-                try
+                async Task<TResult> Core()
                 {
-                    do
+                    var value = default(TResult);
+
+                    var e = source.GetAsyncEnumerator(cancellationToken);
+
+                    try
                     {
-                        if (!await e.MoveNextAsync().ConfigureAwait(false))
+                        do
                         {
-                            return value;
-                        }
+                            if (!await e.MoveNextAsync().ConfigureAwait(false))
+                            {
+                                return value;
+                            }
 
-                        value = selector(e.Current);
-                    }
-                    while (value == null);
+                            value = selector(e.Current);
+                        }
+                        while (value == null);
 
-                    while (await e.MoveNextAsync().ConfigureAwait(false))
-                    {
-                        var x = selector(e.Current);
-                        if (x != null && comparer.Compare(x, value) > 0)
+                        while (await e.MoveNextAsync().ConfigureAwait(false))
                         {
-                            value = x;
+                            var x = selector(e.Current);
+                            if (x != null && comparer.Compare(x, value) > 0)
+                            {
+                                value = x;
+                            }
                         }
                     }
-                }
-                finally
-                {
-                    await e.DisposeAsync().ConfigureAwait(false);
+                    finally
+                    {
+                        await e.DisposeAsync().ConfigureAwait(false);
+                    }
+
+                    return value;
                 }
             }
             else
             {
-                var e = source.GetAsyncEnumerator(cancellationToken);
+                return Core();
 
-                try
+                async Task<TResult> Core()
                 {
-                    if (!await e.MoveNextAsync().ConfigureAwait(false))
-                    {
-                        throw Error.NoElements();
-                    }
+                    var value = default(TResult);
+
+                    var e = source.GetAsyncEnumerator(cancellationToken);
 
-                    value = selector(e.Current);
-                    while (await e.MoveNextAsync().ConfigureAwait(false))
+                    try
                     {
-                        var x = selector(e.Current);
-                        if (comparer.Compare(x, value) > 0)
+                        if (!await e.MoveNextAsync().ConfigureAwait(false))
+                        {
+                            throw Error.NoElements();
+                        }
+
+                        value = selector(e.Current);
+                        while (await e.MoveNextAsync().ConfigureAwait(false))
                         {
-                            value = x;
+                            var x = selector(e.Current);
+                            if (comparer.Compare(x, value) > 0)
+                            {
+                                value = x;
+                            }
                         }
                     }
-                }
-                finally
-                {
-                    await e.DisposeAsync().ConfigureAwait(false);
+                    finally
+                    {
+                        await e.DisposeAsync().ConfigureAwait(false);
+                    }
+
+                    return value;
                 }
             }
-
-            return value;
         }
 
-        private static async Task<TResult> MaxCore<TSource, TResult>(IAsyncEnumerable<TSource> source, Func<TSource, ValueTask<TResult>> selector, CancellationToken cancellationToken)
+        private static Task<TResult> MaxCore<TSource, TResult>(IAsyncEnumerable<TSource> source, Func<TSource, ValueTask<TResult>> selector, CancellationToken cancellationToken)
         {
             var comparer = Comparer<TResult>.Default;
-            var value = default(TResult);
-            if (value == null)
+            if (default(TResult) == null)
             {
-                var e = source.GetAsyncEnumerator(cancellationToken);
+                return Core();
 
-                try
+                async Task<TResult> Core()
                 {
-                    do
+                    var value = default(TResult);
+
+                    var e = source.GetAsyncEnumerator(cancellationToken);
+
+                    try
                     {
-                        if (!await e.MoveNextAsync().ConfigureAwait(false))
+                        do
                         {
-                            return value;
-                        }
+                            if (!await e.MoveNextAsync().ConfigureAwait(false))
+                            {
+                                return value;
+                            }
 
-                        value = await selector(e.Current).ConfigureAwait(false);
-                    }
-                    while (value == null);
+                            value = await selector(e.Current).ConfigureAwait(false);
+                        }
+                        while (value == null);
 
-                    while (await e.MoveNextAsync().ConfigureAwait(false))
-                    {
-                        var x = await selector(e.Current).ConfigureAwait(false);
-                        if (x != null && comparer.Compare(x, value) > 0)
+                        while (await e.MoveNextAsync().ConfigureAwait(false))
                         {
-                            value = x;
+                            var x = await selector(e.Current).ConfigureAwait(false);
+                            if (x != null && comparer.Compare(x, value) > 0)
+                            {
+                                value = x;
+                            }
                         }
                     }
-                }
-                finally
-                {
-                    await e.DisposeAsync().ConfigureAwait(false);
+                    finally
+                    {
+                        await e.DisposeAsync().ConfigureAwait(false);
+                    }
+
+                    return value;
                 }
             }
             else
             {
-                var e = source.GetAsyncEnumerator(cancellationToken);
+                return Core();
 
-                try
+                async Task<TResult> Core()
                 {
-                    if (!await e.MoveNextAsync().ConfigureAwait(false))
-                    {
-                        throw Error.NoElements();
-                    }
+                    var value = default(TResult);
+
+                    var e = source.GetAsyncEnumerator(cancellationToken);
 
-                    value = await selector(e.Current).ConfigureAwait(false);
-                    while (await e.MoveNextAsync().ConfigureAwait(false))
+                    try
                     {
-                        var x = await selector(e.Current).ConfigureAwait(false);
-                        if (comparer.Compare(x, value) > 0)
+                        if (!await e.MoveNextAsync().ConfigureAwait(false))
+                        {
+                            throw Error.NoElements();
+                        }
+
+                        value = await selector(e.Current).ConfigureAwait(false);
+                        while (await e.MoveNextAsync().ConfigureAwait(false))
                         {
-                            value = x;
+                            var x = await selector(e.Current).ConfigureAwait(false);
+                            if (comparer.Compare(x, value) > 0)
+                            {
+                                value = x;
+                            }
                         }
                     }
-                }
-                finally
-                {
-                    await e.DisposeAsync().ConfigureAwait(false);
+                    finally
+                    {
+                        await e.DisposeAsync().ConfigureAwait(false);
+                    }
+
+                    return value;
                 }
             }
-
-            return value;
         }
 
 #if !NO_DEEP_CANCELLATION
-        private static async Task<TResult> MaxCore<TSource, TResult>(IAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, ValueTask<TResult>> selector, CancellationToken cancellationToken)
+        private static Task<TResult> MaxCore<TSource, TResult>(IAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, ValueTask<TResult>> selector, CancellationToken cancellationToken)
         {
             var comparer = Comparer<TResult>.Default;
-            var value = default(TResult);
-            if (value == null)
+            if (default(TResult) == null)
             {
-                var e = source.GetAsyncEnumerator(cancellationToken);
+                return Core();
 
-                try
+                async Task<TResult> Core()
                 {
-                    do
+                    var value = default(TResult);
+
+                    var e = source.GetAsyncEnumerator(cancellationToken);
+
+                    try
                     {
-                        if (!await e.MoveNextAsync().ConfigureAwait(false))
+                        do
                         {
-                            return value;
-                        }
+                            if (!await e.MoveNextAsync().ConfigureAwait(false))
+                            {
+                                return value;
+                            }
 
-                        value = await selector(e.Current, cancellationToken).ConfigureAwait(false);
-                    }
-                    while (value == null);
+                            value = await selector(e.Current, cancellationToken).ConfigureAwait(false);
+                        }
+                        while (value == null);
 
-                    while (await e.MoveNextAsync().ConfigureAwait(false))
-                    {
-                        var x = await selector(e.Current, cancellationToken).ConfigureAwait(false);
-                        if (x != null && comparer.Compare(x, value) > 0)
+                        while (await e.MoveNextAsync().ConfigureAwait(false))
                         {
-                            value = x;
+                            var x = await selector(e.Current, cancellationToken).ConfigureAwait(false);
+                            if (x != null && comparer.Compare(x, value) > 0)
+                            {
+                                value = x;
+                            }
                         }
                     }
-                }
-                finally
-                {
-                    await e.DisposeAsync().ConfigureAwait(false);
+                    finally
+                    {
+                        await e.DisposeAsync().ConfigureAwait(false);
+                    }
+
+                    return value;
                 }
             }
             else
             {
-                var e = source.GetAsyncEnumerator(cancellationToken);
+                return Core();
 
-                try
+                async Task<TResult> Core()
                 {
-                    if (!await e.MoveNextAsync().ConfigureAwait(false))
-                    {
-                        throw Error.NoElements();
-                    }
+                    var value = default(TResult);
+
+                    var e = source.GetAsyncEnumerator(cancellationToken);
 
-                    value = await selector(e.Current, cancellationToken).ConfigureAwait(false);
-                    while (await e.MoveNextAsync().ConfigureAwait(false))
+                    try
                     {
-                        var x = await selector(e.Current, cancellationToken).ConfigureAwait(false);
-                        if (comparer.Compare(x, value) > 0)
+                        if (!await e.MoveNextAsync().ConfigureAwait(false))
+                        {
+                            throw Error.NoElements();
+                        }
+
+                        value = await selector(e.Current, cancellationToken).ConfigureAwait(false);
+                        while (await e.MoveNextAsync().ConfigureAwait(false))
                         {
-                            value = x;
+                            var x = await selector(e.Current, cancellationToken).ConfigureAwait(false);
+                            if (comparer.Compare(x, value) > 0)
+                            {
+                                value = x;
+                            }
                         }
                     }
-                }
-                finally
-                {
-                    await e.DisposeAsync().ConfigureAwait(false);
+                    finally
+                    {
+                        await e.DisposeAsync().ConfigureAwait(false);
+                    }
+
+                    return value;
                 }
             }
-
-            return value;
         }
 #endif
     }

+ 212 - 152
Ix.NET/Source/System.Linq.Async/System/Linq/Operators/Min.Generic.cs

@@ -10,265 +10,325 @@ namespace System.Linq
 {
     public static partial class AsyncEnumerable
     {
-        private static async Task<TSource> MinCore<TSource>(IAsyncEnumerable<TSource> source, CancellationToken cancellationToken)
+        private static Task<TSource> MinCore<TSource>(IAsyncEnumerable<TSource> source, CancellationToken cancellationToken)
         {
             var comparer = Comparer<TSource>.Default;
-            var value = default(TSource);
-            if (value == null)
+            if (default(TSource) == null)
             {
-                var e = source.GetAsyncEnumerator(cancellationToken);
+                return Core();
 
-                try
+                async Task<TSource> Core()
                 {
-                    do
+                    var value = default(TSource);
+
+                    var e = source.GetAsyncEnumerator(cancellationToken);
+
+                    try
                     {
-                        if (!await e.MoveNextAsync().ConfigureAwait(false))
+                        do
                         {
-                            return value;
-                        }
+                            if (!await e.MoveNextAsync().ConfigureAwait(false))
+                            {
+                                return value;
+                            }
 
-                        value = e.Current;
-                    }
-                    while (value == null);
+                            value = e.Current;
+                        }
+                        while (default(TSource) == null);
 
-                    while (await e.MoveNextAsync().ConfigureAwait(false))
-                    {
-                        var x = e.Current;
-                        if (x != null && comparer.Compare(x, value) < 0)
+                        while (await e.MoveNextAsync().ConfigureAwait(false))
                         {
-                            value = x;
+                            var x = e.Current;
+                            if (x != null && comparer.Compare(x, value) < 0)
+                            {
+                                value = x;
+                            }
                         }
                     }
-                }
-                finally
-                {
-                    await e.DisposeAsync().ConfigureAwait(false);
+                    finally
+                    {
+                        await e.DisposeAsync().ConfigureAwait(false);
+                    }
+
+                    return value;
                 }
             }
             else
             {
-                var e = source.GetAsyncEnumerator(cancellationToken);
+                return Core();
 
-                try
+                async Task<TSource> Core()
                 {
-                    if (!await e.MoveNextAsync().ConfigureAwait(false))
-                    {
-                        throw Error.NoElements();
-                    }
+                    var value = default(TSource);
+
+                    var e = source.GetAsyncEnumerator(cancellationToken);
 
-                    value = e.Current;
-                    while (await e.MoveNextAsync().ConfigureAwait(false))
+                    try
                     {
-                        var x = e.Current;
-                        if (comparer.Compare(x, value) < 0)
+                        if (!await e.MoveNextAsync().ConfigureAwait(false))
+                        {
+                            throw Error.NoElements();
+                        }
+
+                        value = e.Current;
+                        while (await e.MoveNextAsync().ConfigureAwait(false))
                         {
-                            value = x;
+                            var x = e.Current;
+                            if (comparer.Compare(x, value) < 0)
+                            {
+                                value = x;
+                            }
                         }
                     }
-                }
-                finally
-                {
-                    await e.DisposeAsync().ConfigureAwait(false);
+                    finally
+                    {
+                        await e.DisposeAsync().ConfigureAwait(false);
+                    }
+
+                    return value;
                 }
             }
-
-            return value;
         }
 
-        private static async Task<TResult> MinCore<TSource, TResult>(IAsyncEnumerable<TSource> source, Func<TSource, TResult> selector, CancellationToken cancellationToken)
+        private static Task<TResult> MinCore<TSource, TResult>(IAsyncEnumerable<TSource> source, Func<TSource, TResult> selector, CancellationToken cancellationToken)
         {
             var comparer = Comparer<TResult>.Default;
-            var value = default(TResult);
-            if (value == null)
+            if (default(TResult) == null)
             {
-                var e = source.GetAsyncEnumerator(cancellationToken);
+                return Core();
 
-                try
+                async Task<TResult> Core()
                 {
-                    do
+                    var value = default(TResult);
+
+                    var e = source.GetAsyncEnumerator(cancellationToken);
+
+                    try
                     {
-                        if (!await e.MoveNextAsync().ConfigureAwait(false))
+                        do
                         {
-                            return value;
-                        }
+                            if (!await e.MoveNextAsync().ConfigureAwait(false))
+                            {
+                                return value;
+                            }
 
-                        value = selector(e.Current);
-                    }
-                    while (value == null);
+                            value = selector(e.Current);
+                        }
+                        while (default(TSource) == null);
 
-                    while (await e.MoveNextAsync().ConfigureAwait(false))
-                    {
-                        var x = selector(e.Current);
-                        if (x != null && comparer.Compare(x, value) < 0)
+                        while (await e.MoveNextAsync().ConfigureAwait(false))
                         {
-                            value = x;
+                            var x = selector(e.Current);
+                            if (x != null && comparer.Compare(x, value) < 0)
+                            {
+                                value = x;
+                            }
                         }
                     }
-                }
-                finally
-                {
-                    await e.DisposeAsync().ConfigureAwait(false);
+                    finally
+                    {
+                        await e.DisposeAsync().ConfigureAwait(false);
+                    }
+
+                    return value;
                 }
             }
             else
             {
-                var e = source.GetAsyncEnumerator(cancellationToken);
+                return Core();
 
-                try
+                async Task<TResult> Core()
                 {
-                    if (!await e.MoveNextAsync().ConfigureAwait(false))
-                    {
-                        throw Error.NoElements();
-                    }
+                    var value = default(TResult);
+
+                    var e = source.GetAsyncEnumerator(cancellationToken);
 
-                    value = selector(e.Current);
-                    while (await e.MoveNextAsync().ConfigureAwait(false))
+                    try
                     {
-                        var x = selector(e.Current);
-                        if (comparer.Compare(x, value) < 0)
+                        if (!await e.MoveNextAsync().ConfigureAwait(false))
+                        {
+                            throw Error.NoElements();
+                        }
+
+                        value = selector(e.Current);
+                        while (await e.MoveNextAsync().ConfigureAwait(false))
                         {
-                            value = x;
+                            var x = selector(e.Current);
+                            if (comparer.Compare(x, value) < 0)
+                            {
+                                value = x;
+                            }
                         }
                     }
-                }
-                finally
-                {
-                    await e.DisposeAsync().ConfigureAwait(false);
+                    finally
+                    {
+                        await e.DisposeAsync().ConfigureAwait(false);
+                    }
+
+                    return value;
                 }
             }
-
-            return value;
         }
 
-        private static async Task<TResult> MinCore<TSource, TResult>(IAsyncEnumerable<TSource> source, Func<TSource, ValueTask<TResult>> selector, CancellationToken cancellationToken)
+        private static Task<TResult> MinCore<TSource, TResult>(IAsyncEnumerable<TSource> source, Func<TSource, ValueTask<TResult>> selector, CancellationToken cancellationToken)
         {
             var comparer = Comparer<TResult>.Default;
-            var value = default(TResult);
-            if (value == null)
+            if (default(TResult) == null)
             {
-                var e = source.GetAsyncEnumerator(cancellationToken);
+                return Core();
 
-                try
+                async Task<TResult> Core()
                 {
-                    do
+                    var value = default(TResult);
+
+                    var e = source.GetAsyncEnumerator(cancellationToken);
+
+                    try
                     {
-                        if (!await e.MoveNextAsync().ConfigureAwait(false))
+                        do
                         {
-                            return value;
-                        }
+                            if (!await e.MoveNextAsync().ConfigureAwait(false))
+                            {
+                                return value;
+                            }
 
-                        value = await selector(e.Current).ConfigureAwait(false);
-                    }
-                    while (value == null);
+                            value = await selector(e.Current).ConfigureAwait(false);
+                        }
+                        while (default(TSource) == null);
 
-                    while (await e.MoveNextAsync().ConfigureAwait(false))
-                    {
-                        var x = await selector(e.Current).ConfigureAwait(false);
-                        if (x != null && comparer.Compare(x, value) < 0)
+                        while (await e.MoveNextAsync().ConfigureAwait(false))
                         {
-                            value = x;
+                            var x = await selector(e.Current).ConfigureAwait(false);
+                            if (x != null && comparer.Compare(x, value) < 0)
+                            {
+                                value = x;
+                            }
                         }
                     }
-                }
-                finally
-                {
-                    await e.DisposeAsync().ConfigureAwait(false);
+                    finally
+                    {
+                        await e.DisposeAsync().ConfigureAwait(false);
+                    }
+
+                    return value;
                 }
             }
             else
             {
-                var e = source.GetAsyncEnumerator(cancellationToken);
+                return Core();
 
-                try
+                async Task<TResult> Core()
                 {
-                    if (!await e.MoveNextAsync().ConfigureAwait(false))
-                    {
-                        throw Error.NoElements();
-                    }
+                    var value = default(TResult);
+
+                    var e = source.GetAsyncEnumerator(cancellationToken);
 
-                    value = await selector(e.Current).ConfigureAwait(false);
-                    while (await e.MoveNextAsync().ConfigureAwait(false))
+                    try
                     {
-                        var x = await selector(e.Current).ConfigureAwait(false);
-                        if (comparer.Compare(x, value) < 0)
+                        if (!await e.MoveNextAsync().ConfigureAwait(false))
+                        {
+                            throw Error.NoElements();
+                        }
+
+                        value = await selector(e.Current).ConfigureAwait(false);
+                        while (await e.MoveNextAsync().ConfigureAwait(false))
                         {
-                            value = x;
+                            var x = await selector(e.Current).ConfigureAwait(false);
+                            if (comparer.Compare(x, value) < 0)
+                            {
+                                value = x;
+                            }
                         }
                     }
-                }
-                finally
-                {
-                    await e.DisposeAsync().ConfigureAwait(false);
+                    finally
+                    {
+                        await e.DisposeAsync().ConfigureAwait(false);
+                    }
+
+                    return value;
                 }
             }
-
-            return value;
         }
 
 #if !NO_DEEP_CANCELLATION
-        private static async Task<TResult> MinCore<TSource, TResult>(IAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, ValueTask<TResult>> selector, CancellationToken cancellationToken)
+        private static Task<TResult> MinCore<TSource, TResult>(IAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, ValueTask<TResult>> selector, CancellationToken cancellationToken)
         {
             var comparer = Comparer<TResult>.Default;
-            var value = default(TResult);
-            if (value == null)
+            if (default(TResult) == null)
             {
-                var e = source.GetAsyncEnumerator(cancellationToken);
+                return Core();
 
-                try
+                async Task<TResult> Core()
                 {
-                    do
+                    var value = default(TResult);
+
+                    var e = source.GetAsyncEnumerator(cancellationToken);
+
+                    try
                     {
-                        if (!await e.MoveNextAsync().ConfigureAwait(false))
+                        do
                         {
-                            return value;
-                        }
+                            if (!await e.MoveNextAsync().ConfigureAwait(false))
+                            {
+                                return value;
+                            }
 
-                        value = await selector(e.Current, cancellationToken).ConfigureAwait(false);
-                    }
-                    while (value == null);
+                            value = await selector(e.Current, cancellationToken).ConfigureAwait(false);
+                        }
+                        while (default(TSource) == null);
 
-                    while (await e.MoveNextAsync().ConfigureAwait(false))
-                    {
-                        var x = await selector(e.Current, cancellationToken).ConfigureAwait(false);
-                        if (x != null && comparer.Compare(x, value) < 0)
+                        while (await e.MoveNextAsync().ConfigureAwait(false))
                         {
-                            value = x;
+                            var x = await selector(e.Current, cancellationToken).ConfigureAwait(false);
+                            if (x != null && comparer.Compare(x, value) < 0)
+                            {
+                                value = x;
+                            }
                         }
                     }
-                }
-                finally
-                {
-                    await e.DisposeAsync().ConfigureAwait(false);
+                    finally
+                    {
+                        await e.DisposeAsync().ConfigureAwait(false);
+                    }
+
+                    return value;
                 }
             }
             else
             {
-                var e = source.GetAsyncEnumerator(cancellationToken);
+                return Core();
 
-                try
+                async Task<TResult> Core()
                 {
-                    if (!await e.MoveNextAsync().ConfigureAwait(false))
-                    {
-                        throw Error.NoElements();
-                    }
+                    var value = default(TResult);
+
+                    var e = source.GetAsyncEnumerator(cancellationToken);
 
-                    value = await selector(e.Current, cancellationToken).ConfigureAwait(false);
-                    while (await e.MoveNextAsync().ConfigureAwait(false))
+                    try
                     {
-                        var x = await selector(e.Current, cancellationToken).ConfigureAwait(false);
-                        if (comparer.Compare(x, value) < 0)
+                        if (!await e.MoveNextAsync().ConfigureAwait(false))
+                        {
+                            throw Error.NoElements();
+                        }
+
+                        value = await selector(e.Current, cancellationToken).ConfigureAwait(false);
+                        while (await e.MoveNextAsync().ConfigureAwait(false))
                         {
-                            value = x;
+                            var x = await selector(e.Current, cancellationToken).ConfigureAwait(false);
+                            if (comparer.Compare(x, value) < 0)
+                            {
+                                value = x;
+                            }
                         }
                     }
-                }
-                finally
-                {
-                    await e.DisposeAsync().ConfigureAwait(false);
+                    finally
+                    {
+                        await e.DisposeAsync().ConfigureAwait(false);
+                    }
+
+                    return value;
                 }
             }
-
-            return value;
         }
 #endif
     }