public static bool IsAsyncEnumerable(this ITypeSymbol typeSymbol, Compilation compilation, out AsyncEnumerableSymbols enumerableSymbols)
        {
            if (typeSymbol is null)
            {
                throw new ArgumentNullException(nameof(typeSymbol));
            }
            if (compilation is null)
            {
                throw new ArgumentNullException(nameof(compilation));
            }

            if (!typeSymbol.IsAsyncEnumerableType(compilation, out var getEnumerator))
            {
                enumerableSymbols = default;
                return(false);
            }

            var isAsyncEnumerator = getEnumerator.ReturnType.IsAsyncEnumeratorType(compilation, out var current, out var moveNext, out var dispose);

            enumerableSymbols = new AsyncEnumerableSymbols(getEnumerator, new AsyncEnumeratorSymbols(current, moveNext, dispose));
            return(isAsyncEnumerator);
        }
        /// <summary>
        /// Gets a value indicating whether 'await foreach' considers <see cref="Microsoft.CodeAnalysis.ITypeSymbol"/> to be enumerable.
        /// </summary>
        /// <param name="typeSymbol">The <see cref="Microsoft.CodeAnalysis.ITypeSymbol"/> to test.</param>
        /// <param name="compilation">The <see cref="Microsoft.CodeAnalysis.Compilation"/> context.</param>
        /// <param name="enumerableSymbols">If methods returns <c>true</c>, contains information on the methods 'await foreach' will use to enumerate.</param>
        /// <param name="errors">Gets information on what error caused the method to return <c>false</c>.</param>
        /// <returns><c>true</c> if 'await foreach' considers <see cref="Microsoft.CodeAnalysis.ITypeSymbol"/> to be enumerable; otherwise, <c>false</c>.</returns>
        public static bool IsAsyncEnumerable(this ITypeSymbol typeSymbol, Compilation compilation,
                                             [NotNullWhen(true)] out AsyncEnumerableSymbols?enumerableSymbols,
                                             out Errors errors)
        {
            if (typeSymbol.TypeKind != TypeKind.Interface)
            {
                var getEnumerator =
                    typeSymbol.GetPublicMethod("GetAsyncEnumerator", typeof(CancellationToken))
                    ?? typeSymbol.GetPublicMethod("GetAsyncEnumerator");

                if (getEnumerator is not null)
                {
                    var enumeratorType = getEnumerator.ReturnType;

                    var current = enumeratorType.GetPublicReadProperty("Current");
                    if (current is null)
                    {
                        enumerableSymbols = default;
                        errors            = Errors.MissingCurrent;
                        return(false);
                    }

                    var moveNext = enumeratorType.GetPublicMethod("MoveNextAsync");
                    if (moveNext is null)
                    {
                        enumerableSymbols = default;
                        errors            = Errors.MissingMoveNext;
                        return(false);
                    }

                    _ = enumeratorType.IsAsyncDisposable(compilation, out var dispose);

                    enumerableSymbols = new AsyncEnumerableSymbols(
                        getEnumerator,
                        new AsyncEnumeratorSymbols(current, moveNext)
                    {
                        DisposeAsync = dispose,
                        IsValueType  = getEnumerator.ReturnType.IsValueType,
                        IsAsyncEnumeratorInterface = enumeratorType.TypeKind == TypeKind.Interface,
                    }
                        );
                    errors = Errors.None;
                    return(true);
                }
            }

            var asyncEnumerableType = compilation.GetTypeByMetadataName("System.Collections.Generic.IAsyncEnumerable`1") !;

            if (typeSymbol.ImplementsInterface(asyncEnumerableType, out var genericArguments))
            {
                var asyncEnumeratorType = compilation.GetTypeByMetadataName("System.Collections.Generic.IAsyncEnumerator`1") !.Construct(genericArguments[0]);
                var asyncDisposableType = compilation.GetTypeByMetadataName("System.IAsyncDisposable") !;

                enumerableSymbols = new AsyncEnumerableSymbols(
                    asyncEnumerableType.GetPublicMethod("GetAsyncEnumerator", typeof(CancellationToken)) !,
                    new AsyncEnumeratorSymbols(
                        asyncEnumeratorType.GetPublicReadProperty("Current") !,
                        asyncEnumeratorType.GetPublicMethod("MoveNextAsync", Type.EmptyTypes) !)
                {
                    DisposeAsync = asyncDisposableType.GetPublicMethod("DisposeAsync", Type.EmptyTypes),
                    IsAsyncEnumeratorInterface = true,
                }