Repository: PowerShell/PowerShell
File: src/System.Management.Automation/engine/parser/SymbolResolver.cs (C#)

Code before:
        }

        private bool VisitGenericTypeName(GenericTypeName genericTypeName)
        {
            var foundType = TypeCache.Lookup(genericTypeName, _typeResolutionState);
            if (foundType != null)
            {
                ((ISupportsTypeCaching)genericTypeName).CachedType = foundType;

                // When the generic type is in cache, we won't go through the code path that resolves
                // 'genericTypeName.TypeName', which represents the generic type definition.
                //
                // - We could get the type definition by 'genericTypeName.TypeName.GetReflectionType()'
                //   in some cases, for example, when the generic type is 'System.Tuple[string, string]',
                //   calling 'GetReflectionType()' returns the 'System.Tuple' type.
                //
                // - But in much more other cases, calling that method won't return the type definition,
                //   for example, when the generic type is 'System.Collections.Generic.List[string]',
                //   the call returns 'null' because 'System.Collections.Generic.List' is not a valid type.
                //
                // In the latter cases, given that we already have the generic type, we can get the type
                // definition and assign it to the cached type of 'genericTypeName.TypeName'.
                var genericDefinition = genericTypeName.TypeName;
                if (genericDefinition.GetReflectionType() is null)
                {
                    ((ISupportsTypeCaching)genericDefinition).CachedType = foundType.GetGenericTypeDefinition();
                }

                return true;
            }

            bool resolved = true;
            resolved &= DispatchTypeName(genericTypeName.TypeName, genericTypeName.GenericArguments.Count, isAttribute: false);
            foreach (var typeArg in genericTypeName.GenericArguments)
            {
                resolved &= DispatchTypeName(typeArg, genericArgumentCount: 0, isAttribute: false);
            }

            if (resolved)
            {
                var resolvedType = genericTypeName.GetReflectionType();
                TypeCache.Add(genericTypeName, _typeResolutionState, resolvedType);
            }

            return resolved;
        }

        public void PostVisit(Ast ast)
        {
            ast.Accept(_symbolResolvePostActionVisitor);
        }

Review comment (performance):
I wonder if previously we already put genericTypeName in cache why didn't we the assignment in that time?

Code after:
        }

        private bool VisitGenericTypeName(GenericTypeName genericTypeName)
        {
            var foundType = TypeCache.Lookup(genericTypeName, _typeResolutionState);
            if (foundType != null)
            {
                ((ISupportsTypeCaching)genericTypeName).CachedType = foundType;
                return true;
            }

            bool resolved = true;
            resolved &= DispatchTypeName(genericTypeName.TypeName, genericTypeName.GenericArguments.Count, isAttribute: false);
            foreach (var typeArg in genericTypeName.GenericArguments)
            {
                resolved &= DispatchTypeName(typeArg, genericArgumentCount: 0, isAttribute: false);
            }

            if (resolved)
            {
                var resolvedType = genericTypeName.GetReflectionType();
                TypeCache.Add(genericTypeName, _typeResolutionState, resolvedType);
            }

            return resolved;
        }

        public void PostVisit(Ast ast)
        {
            ast.Accept(_symbolResolvePostActionVisitor);
        }

        internal static string GetModuleQualifiedName(string namespaceName, string typeName)
        {
            const char NAMESPACE_SEPARATOR = '.';
            return namespaceName + NAMESPACE_SEPARATOR + typeName;
        }
    }

    internal class SymbolResolvePostActionVisitor : DefaultCustomAstVisitor2
    {
        internal SymbolResolver _symbolResolver;

        public override object VisitFunctionDefinition(FunctionDefinitionAst functionDefinitionAst)
        {
            if (functionDefinitionAst.Parent is not FunctionMemberAst)
            {
                _symbolResolver._symbolTable.LeaveScope();
            }

            return null;