diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index b8dd117d6f..5d2b0187eb 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -10294,65 +10294,69 @@ namespace ts { return getConditionalType(root, mapper); } - function instantiateWithDepthCheck(type: Type, mapper: TypeMapper, instantiator: (type: Type, mapper: TypeMapper) => Type): Type { - if (instantiationDepth < 50) { - instantiationDepth++; - const result = instantiator(type, mapper); - instantiationDepth--; - return result; - } - // We have reached 50 recursive type instantiations and there is a very high likelyhood we're dealing - // with a combination of infinite generic types that perpetually generate new type identities. We stop - // the recursion here by yielding the error type. - return errorType; - } - function instantiateType(type: Type, mapper: TypeMapper | undefined): Type; function instantiateType(type: Type | undefined, mapper: TypeMapper | undefined): Type | undefined; function instantiateType(type: Type | undefined, mapper: TypeMapper | undefined): Type | undefined { - if (type && mapper && mapper !== identityMapper) { - if (type.flags & TypeFlags.TypeParameter) { - return mapper(type); + if (!type || !mapper || mapper === identityMapper) { + return type; + } + if (instantiationDepth === 50) { + // We have reached 50 recursive type instantiations and there is a very high likelyhood we're dealing + // with a combination of infinite generic types that perpetually generate new type identities. We stop + // the recursion here by yielding the error type. + return errorType; + } + instantiationDepth++; + const result = instantiateTypeWorker(type, mapper); + instantiationDepth--; + return result; + } + + function instantiateTypeWorker(type: Type, mapper: TypeMapper): Type { + const flags = type.flags; + if (flags & TypeFlags.TypeParameter) { + return mapper(type); + } + if (flags & TypeFlags.Object) { + const objectFlags = (type).objectFlags; + if (objectFlags & ObjectFlags.Anonymous) { + // If the anonymous type originates in a declaration of a function, method, class, or + // interface, in an object type literal, or in an object literal expression, we may need + // to instantiate the type because it might reference a type parameter. + return type.symbol && type.symbol.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.Class | SymbolFlags.TypeLiteral | SymbolFlags.ObjectLiteral) && type.symbol.declarations ? + getAnonymousTypeInstantiation(type, mapper) : type; } - if (type.flags & TypeFlags.Object) { - if ((type).objectFlags & ObjectFlags.Anonymous) { - // If the anonymous type originates in a declaration of a function, method, class, or - // interface, in an object type literal, or in an object literal expression, we may need - // to instantiate the type because it might reference a type parameter. - return type.symbol && type.symbol.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.Class | SymbolFlags.TypeLiteral | SymbolFlags.ObjectLiteral) && type.symbol.declarations ? - instantiateWithDepthCheck(type, mapper, getAnonymousTypeInstantiation) : type; - } - if ((type).objectFlags & ObjectFlags.Mapped) { - return instantiateWithDepthCheck(type, mapper, getAnonymousTypeInstantiation); - } - if ((type).objectFlags & ObjectFlags.Reference) { - const typeArguments = (type).typeArguments; - const newTypeArguments = instantiateTypes(typeArguments, mapper); - return newTypeArguments !== typeArguments ? createTypeReference((type).target, newTypeArguments) : type; - } + if (objectFlags & ObjectFlags.Mapped) { + return getAnonymousTypeInstantiation(type, mapper); } - if (type.flags & TypeFlags.Union && !(type.flags & TypeFlags.Primitive)) { - const types = (type).types; - const newTypes = instantiateTypes(types, mapper); - return newTypes !== types ? getUnionType(newTypes, UnionReduction.Literal, type.aliasSymbol, instantiateTypes(type.aliasTypeArguments, mapper)) : type; - } - if (type.flags & TypeFlags.Intersection) { - const types = (type).types; - const newTypes = instantiateTypes(types, mapper); - return newTypes !== types ? getIntersectionType(newTypes, type.aliasSymbol, instantiateTypes(type.aliasTypeArguments, mapper)) : type; - } - if (type.flags & TypeFlags.Index) { - return getIndexType(instantiateType((type).type, mapper)); - } - if (type.flags & TypeFlags.IndexedAccess) { - return getIndexedAccessType(instantiateType((type).objectType, mapper), instantiateType((type).indexType, mapper)); - } - if (type.flags & TypeFlags.Conditional) { - return instantiateWithDepthCheck(type, combineTypeMappers((type).mapper, mapper), getConditionalTypeInstantiation); - } - if (type.flags & TypeFlags.Substitution) { - return instantiateType((type).typeVariable, mapper); + if (objectFlags & ObjectFlags.Reference) { + const typeArguments = (type).typeArguments; + const newTypeArguments = instantiateTypes(typeArguments, mapper); + return newTypeArguments !== typeArguments ? createTypeReference((type).target, newTypeArguments) : type; } + return type; + } + if (flags & TypeFlags.Union && !(flags & TypeFlags.Primitive)) { + const types = (type).types; + const newTypes = instantiateTypes(types, mapper); + return newTypes !== types ? getUnionType(newTypes, UnionReduction.Literal, type.aliasSymbol, instantiateTypes(type.aliasTypeArguments, mapper)) : type; + } + if (flags & TypeFlags.Intersection) { + const types = (type).types; + const newTypes = instantiateTypes(types, mapper); + return newTypes !== types ? getIntersectionType(newTypes, type.aliasSymbol, instantiateTypes(type.aliasTypeArguments, mapper)) : type; + } + if (flags & TypeFlags.Index) { + return getIndexType(instantiateType((type).type, mapper)); + } + if (flags & TypeFlags.IndexedAccess) { + return getIndexedAccessType(instantiateType((type).objectType, mapper), instantiateType((type).indexType, mapper)); + } + if (flags & TypeFlags.Conditional) { + return getConditionalTypeInstantiation(type, combineTypeMappers((type).mapper, mapper)); + } + if (flags & TypeFlags.Substitution) { + return instantiateType((type).typeVariable, mapper); } return type; }