@@ -53,7 +53,8 @@ namespace ts {
53
53
let typeCount = 0;
54
54
let symbolCount = 0;
55
55
let enumCount = 0;
56
- let symbolInstantiationDepth = 0;
56
+ let instantiationDepth = 0;
57
+ let constraintDepth = 0;
57
58
58
59
const emptySymbols = createSymbolTable();
59
60
const identityMapper: (type: Type) => Type = identity;
@@ -5295,22 +5296,14 @@ namespace ts {
5295
5296
function getTypeOfInstantiatedSymbol(symbol: Symbol): Type {
5296
5297
const links = getSymbolLinks(symbol);
5297
5298
if (!links.type) {
5298
- if (symbolInstantiationDepth === 100) {
5299
- error(symbol.valueDeclaration, Diagnostics.Generic_type_instantiation_is_excessively_deep_and_possibly_infinite);
5300
- links.type = errorType;
5299
+ if (!pushTypeResolution(symbol, TypeSystemPropertyName.Type)) {
5300
+ return links.type = errorType;
5301
5301
}
5302
- else {
5303
- if (!pushTypeResolution(symbol, TypeSystemPropertyName.Type)) {
5304
- return links.type = errorType;
5305
- }
5306
- symbolInstantiationDepth++;
5307
- let type = instantiateType(getTypeOfSymbol(links.target!), links.mapper!);
5308
- symbolInstantiationDepth--;
5309
- if (!popTypeResolution()) {
5310
- type = reportCircularityError(symbol);
5311
- }
5312
- links.type = type;
5302
+ let type = instantiateType(getTypeOfSymbol(links.target!), links.mapper!);
5303
+ if (!popTypeResolution()) {
5304
+ type = reportCircularityError(symbol);
5313
5305
}
5306
+ links.type = type;
5314
5307
}
5315
5308
return links.type;
5316
5309
}
@@ -7003,6 +6996,7 @@ namespace ts {
7003
6996
* circularly references the type variable.
7004
6997
*/
7005
6998
function getResolvedBaseConstraint(type: InstantiableType | UnionOrIntersectionType): Type {
6999
+ let nonTerminating = false;
7006
7000
return type.resolvedBaseConstraint ||
7007
7001
(type.resolvedBaseConstraint = getTypeWithThisArgument(getImmediateBaseConstraint(type), type));
7008
7002
@@ -7011,8 +7005,18 @@ namespace ts {
7011
7005
if (!pushTypeResolution(t, TypeSystemPropertyName.ImmediateBaseConstraint)) {
7012
7006
return circularConstraintType;
7013
7007
}
7008
+ if (constraintDepth === 50) {
7009
+ // We have reached 50 recursive invocations of getImmediateBaseConstraint and there is a
7010
+ // very high likelyhood we're dealing with an infinite generic type that perpetually generates
7011
+ // new type identities as we descend into it. We stop the recursion here and mark this type
7012
+ // and the outer types as having circular constraints.
7013
+ nonTerminating = true;
7014
+ return t.immediateBaseConstraint = noConstraintType;
7015
+ }
7016
+ constraintDepth++;
7014
7017
let result = computeBaseConstraint(getSimplifiedType(t));
7015
- if (!popTypeResolution()) {
7018
+ constraintDepth--;
7019
+ if (!popTypeResolution() || nonTerminating) {
7016
7020
result = circularConstraintType;
7017
7021
}
7018
7022
t.immediateBaseConstraint = result || noConstraintType;
@@ -10282,23 +10286,36 @@ namespace ts {
10282
10286
return getConditionalType(root, mapper);
10283
10287
}
10284
10288
10289
+ function instantiateWithDepthCheck(type: Type, mapper: TypeMapper, instantiator: (type: Type, mapper: TypeMapper) => Type): Type {
10290
+ if (instantiationDepth < 50) {
10291
+ instantiationDepth++;
10292
+ const result = instantiator(type, mapper);
10293
+ instantiationDepth--;
10294
+ return result;
10295
+ }
10296
+ // We have reached 50 recursive type instantiations and there is a very high likelyhood we're dealing
10297
+ // with a combination of infinite generic types that perpetually generate new type identities. We stop
10298
+ // the recursion here by yielding the error type.
10299
+ return errorType;
10300
+ }
10301
+
10285
10302
function instantiateType(type: Type, mapper: TypeMapper | undefined): Type;
10286
10303
function instantiateType(type: Type | undefined, mapper: TypeMapper | undefined): Type | undefined;
10287
10304
function instantiateType(type: Type | undefined, mapper: TypeMapper | undefined): Type | undefined {
10288
10305
if (type && mapper && mapper !== identityMapper) {
10289
10306
if (type.flags & TypeFlags.TypeParameter) {
10290
- return mapper(<TypeParameter> type);
10307
+ return mapper(type);
10291
10308
}
10292
10309
if (type.flags & TypeFlags.Object) {
10293
10310
if ((<ObjectType>type).objectFlags & ObjectFlags.Anonymous) {
10294
10311
// If the anonymous type originates in a declaration of a function, method, class, or
10295
10312
// interface, in an object type literal, or in an object literal expression, we may need
10296
10313
// to instantiate the type because it might reference a type parameter.
10297
10314
return type.symbol && type.symbol.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.Class | SymbolFlags.TypeLiteral | SymbolFlags.ObjectLiteral) && type.symbol.declarations ?
10298
- getAnonymousTypeInstantiation(<AnonymousType> type, mapper) : type;
10315
+ instantiateWithDepthCheck( type, mapper, getAnonymousTypeInstantiation ) : type;
10299
10316
}
10300
10317
if ((<ObjectType>type).objectFlags & ObjectFlags.Mapped) {
10301
- return getAnonymousTypeInstantiation(<MappedType> type, mapper);
10318
+ return instantiateWithDepthCheck( type, mapper, getAnonymousTypeInstantiation );
10302
10319
}
10303
10320
if ((<ObjectType>type).objectFlags & ObjectFlags.Reference) {
10304
10321
const typeArguments = (<TypeReference>type).typeArguments;
@@ -10323,7 +10340,7 @@ namespace ts {
10323
10340
return getIndexedAccessType(instantiateType((<IndexedAccessType>type).objectType, mapper), instantiateType((<IndexedAccessType>type).indexType, mapper));
10324
10341
}
10325
10342
if (type.flags & TypeFlags.Conditional) {
10326
- return getConditionalTypeInstantiation(<ConditionalType> type, combineTypeMappers((<ConditionalType>type).mapper, mapper));
10343
+ return instantiateWithDepthCheck( type, combineTypeMappers((<ConditionalType>type).mapper, mapper), getConditionalTypeInstantiation );
10327
10344
}
10328
10345
if (type.flags & TypeFlags.Substitution) {
10329
10346
return instantiateType((<SubstitutionType>type).typeVariable, mapper);
0 commit comments