Repository: dotnet/roslyn
File: src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs (C#)

Code before:
        /// <param name="useDefaultType">If true, use <see cref="TypeWithAnnotations.DefaultType"/>
        /// instead of <see cref="TypeWithAnnotations.Type"/> to avoid early resolution of nullable types</param>
        public static TypeSymbol? VisitType<T>(
            this TypeWithAnnotations typeWithAnnotationsOpt,
            TypeSymbol? type,
            Func<TypeWithAnnotations, T, bool, bool>? typeWithAnnotationsPredicate,
            Func<TypeSymbol, T, bool, bool>? typePredicate,
            T arg,
            bool canDigThroughNullable = false,
            bool useDefaultType = false,
            bool visitCustomModifiers = false)
        {
            var matchigSymbols = VisitType(
                typeWithAnnotationsOpt: typeWithAnnotationsOpt,
                type: type,
                typeWithAnnotationsPredicate: typeWithAnnotationsPredicate,
                typePredicate: typePredicate,
                arg: arg,
                returnOnMatch: true,
                canDigThroughNullable: canDigThroughNullable,
                useDefaultType: useDefaultType,
                visitCustomModifiers: visitCustomModifiers);
            return matchigSymbols.FirstOrDefault();
        }

        public static List<TypeSymbol> VisitType<T>(
            this TypeWithAnnotations typeWithAnnotationsOpt,
            TypeSymbol? type,
            Func<TypeWithAnnotations, T, bool, bool>? typeWithAnnotationsPredicate,
            Func<TypeSymbol, T, bool, bool>? typePredicate,
            T arg,
            bool returnOnMatch,
            bool canDigThroughNullable = false,
            bool useDefaultType = false,
            bool visitCustomModifiers = false)
        {
            RoslynDebug.Assert(typeWithAnnotationsOpt.HasType == (type is null));
            RoslynDebug.Assert(canDigThroughNullable == false || useDefaultType == false, "digging through nullable will cause early resolution of nullable types");
            RoslynDebug.Assert(canDigThroughNullable == false || visitCustomModifiers == false);
            RoslynDebug.Assert(visitCustomModifiers == false || typePredicate is { });

            List<TypeSymbol> combinedResult = [];

            // In order to handle extremely "deep" types like "int[][][][][][][][][]...[]"
            // or int*****************...* we implement manual tail recursion rather than 
            // doing the natural recursion.

            while (true)
            {
                TypeSymbol current = type ?? (useDefaultType ? typeWithAnnotationsOpt.DefaultType : typeWithAnnotationsOpt.Type);
                bool isNestedNamedType = false;

Review comment (suggestion):
Alternatively i could also collect the TypeSymbols within the typePredicate (and always return _false_) if there are any concerns with my changes to this method

Code after:
                                var result = VisitType(default, containingType, typeWithAnnotationsPredicate, typePredicate, arg, canDigThroughNullable, useDefaultType, visitCustomModifiers);
                                if (result is object)
                                {
                                    return result;
                                }
                            }
                        }
                        break;

                    case TypeKind.Submission:
                        RoslynDebug.Assert((object)current.ContainingType == null);
                        break;
                }

                if (typeWithAnnotationsOpt.HasType && typeWithAnnotationsPredicate != null)
                {
                    if (typeWithAnnotationsPredicate(typeWithAnnotationsOpt, arg, isNestedNamedType))
                    {
                        return current;
                    }
                }
                else if (typePredicate != null)
                {
                    if (typePredicate(current, arg, isNestedNamedType))
                    {
                        return current;
                    }
                }

                if (visitCustomModifiers && typeWithAnnotationsOpt.HasType)
                {
                    foreach (var customModifier in typeWithAnnotationsOpt.CustomModifiers)
                    {
                        var result = VisitType(
                            typeWithAnnotationsOpt: default, type: ((CSharpCustomModifier)customModifier).ModifierSymbol,
                            typeWithAnnotationsPredicate, typePredicate, arg,
                            canDigThroughNullable, useDefaultType, visitCustomModifiers);
                        if (result is object)
                        {
                            return result;
                        }
                    }
                }

                TypeWithAnnotations next;

                switch (current.TypeKind)
                {
                    case TypeKind.Dynamic:
                    case TypeKind.TypeParameter:
                    case TypeKind.Submission: