Perform depth check for all type instantiations
This commit is contained in:
parent
6a81d4c129
commit
7c2644a676
1 changed files with 57 additions and 53 deletions
|
@ -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 = (<ObjectType>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(<AnonymousType>type, mapper) : type;
|
||||
}
|
||||
if (type.flags & TypeFlags.Object) {
|
||||
if ((<ObjectType>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 ((<ObjectType>type).objectFlags & ObjectFlags.Mapped) {
|
||||
return instantiateWithDepthCheck(type, mapper, getAnonymousTypeInstantiation);
|
||||
}
|
||||
if ((<ObjectType>type).objectFlags & ObjectFlags.Reference) {
|
||||
const typeArguments = (<TypeReference>type).typeArguments;
|
||||
const newTypeArguments = instantiateTypes(typeArguments, mapper);
|
||||
return newTypeArguments !== typeArguments ? createTypeReference((<TypeReference>type).target, newTypeArguments) : type;
|
||||
}
|
||||
if (objectFlags & ObjectFlags.Mapped) {
|
||||
return getAnonymousTypeInstantiation(<AnonymousType>type, mapper);
|
||||
}
|
||||
if (type.flags & TypeFlags.Union && !(type.flags & TypeFlags.Primitive)) {
|
||||
const types = (<UnionType>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 = (<IntersectionType>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((<IndexType>type).type, mapper));
|
||||
}
|
||||
if (type.flags & TypeFlags.IndexedAccess) {
|
||||
return getIndexedAccessType(instantiateType((<IndexedAccessType>type).objectType, mapper), instantiateType((<IndexedAccessType>type).indexType, mapper));
|
||||
}
|
||||
if (type.flags & TypeFlags.Conditional) {
|
||||
return instantiateWithDepthCheck(type, combineTypeMappers((<ConditionalType>type).mapper, mapper), getConditionalTypeInstantiation);
|
||||
}
|
||||
if (type.flags & TypeFlags.Substitution) {
|
||||
return instantiateType((<SubstitutionType>type).typeVariable, mapper);
|
||||
if (objectFlags & ObjectFlags.Reference) {
|
||||
const typeArguments = (<TypeReference>type).typeArguments;
|
||||
const newTypeArguments = instantiateTypes(typeArguments, mapper);
|
||||
return newTypeArguments !== typeArguments ? createTypeReference((<TypeReference>type).target, newTypeArguments) : type;
|
||||
}
|
||||
return type;
|
||||
}
|
||||
if (flags & TypeFlags.Union && !(flags & TypeFlags.Primitive)) {
|
||||
const types = (<UnionType>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 = (<IntersectionType>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((<IndexType>type).type, mapper));
|
||||
}
|
||||
if (flags & TypeFlags.IndexedAccess) {
|
||||
return getIndexedAccessType(instantiateType((<IndexedAccessType>type).objectType, mapper), instantiateType((<IndexedAccessType>type).indexType, mapper));
|
||||
}
|
||||
if (flags & TypeFlags.Conditional) {
|
||||
return getConditionalTypeInstantiation(<ConditionalType>type, combineTypeMappers((<ConditionalType>type).mapper, mapper));
|
||||
}
|
||||
if (flags & TypeFlags.Substitution) {
|
||||
return instantiateType((<SubstitutionType>type).typeVariable, mapper);
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue