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

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

            var isEnumerator = getEnumerator.ReturnType.IsEnumeratorType(compilation, out var current, out var moveNext, out var reset, out var dispose);

            enumerableSymbols = new EnumerableSymbols(getEnumerator, new EnumeratorSymbols(current, moveNext, reset, dispose));
            return(isEnumerator);
        }
        /// <summary>
        /// Gets a value indicating whether '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 '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 'foreach' considers <see cref="Microsoft.CodeAnalysis.ITypeSymbol"/> to be enumerable; otherwise, <c>false</c>.</returns>
        public static bool IsEnumerable(this ITypeSymbol typeSymbol, Compilation compilation,
                                        [NotNullWhen(true)] out EnumerableSymbols?enumerableSymbols,
                                        out Errors errors)
        {
            if (typeSymbol.TypeKind != TypeKind.Array && typeSymbol.TypeKind != TypeKind.Interface)
            {
                var getEnumerator = typeSymbol.GetPublicMethod("GetEnumerator");
                if (getEnumerator is not null)
                {
                    var enumeratorType = getEnumerator.ReturnType;

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

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

                    var reset = enumeratorType.GetPublicMethod(nameof(IEnumerator.Reset));
                    _ = enumeratorType.IsDisposable(compilation, out var dispose, out var isRefLike);

                    enumerableSymbols = new EnumerableSymbols(
                        getEnumerator,
                        new EnumeratorSymbols(current, moveNext)
                    {
                        Reset         = reset,
                        Dispose       = dispose,
                        IsValueType   = getEnumerator.ReturnType.IsValueType,
                        IsRefLikeType = isRefLike,
                        IsGenericsEnumeratorInterface =
                            enumeratorType.TypeKind == TypeKind.Interface &&
                            enumeratorType.ImplementsInterface(
                                SpecialType.System_Collections_Generic_IEnumerable_T, out _),
                        IsEnumeratorInterface =
                            enumeratorType.TypeKind == TypeKind.Interface,
                    }
                        );
                    errors = Errors.None;
                    return(true);
                }
            }

            if (typeSymbol.ImplementsInterface(SpecialType.System_Collections_Generic_IEnumerable_T, out var genericArguments))
            {
                var genericEnumerableType = compilation
                                            .GetSpecialType(SpecialType.System_Collections_Generic_IEnumerable_T)
                                            .Construct(genericArguments[0]);
                var genericEnumeratorType = compilation
                                            .GetSpecialType(SpecialType.System_Collections_Generic_IEnumerator_T)
                                            .Construct(genericArguments[0]);
                var enumeratorType = compilation.GetSpecialType(SpecialType.System_Collections_IEnumerator);
                var disposableType = compilation.GetSpecialType(SpecialType.System_IDisposable);

                enumerableSymbols = new EnumerableSymbols(
                    genericEnumerableType.GetPublicMethod(nameof(IEnumerable <int> .GetEnumerator), Type.EmptyTypes) !,
                    new EnumeratorSymbols(
                        genericEnumeratorType.GetPublicReadProperty(nameof(IEnumerator <int> .Current)) !,
                        enumeratorType.GetPublicMethod(nameof(IEnumerator.MoveNext), Type.EmptyTypes) !)
                {
                    Reset   = enumeratorType.GetPublicMethod(nameof(IEnumerator.Reset), Type.EmptyTypes),
                    Dispose = disposableType.GetPublicMethod(nameof(IDisposable.Dispose), Type.EmptyTypes),
                    IsGenericsEnumeratorInterface = true,
                    IsEnumeratorInterface         = true,
                }