@@ -67,6 +67,7 @@ namespace ts {
67
67
let enumCount = 0;
68
68
let instantiationDepth = 0;
69
69
let constraintDepth = 0;
70
+ let currentNode: Node | undefined;
70
71
71
72
const emptySymbols = createSymbolTable();
72
73
const identityMapper: (type: Type) => Type = identity;
@@ -7525,6 +7526,7 @@ namespace ts {
7525
7526
// very high likelyhood we're dealing with an infinite generic type that perpetually generates
7526
7527
// new type identities as we descend into it. We stop the recursion here and mark this type
7527
7528
// and the outer types as having circular constraints.
7529
+ error(currentNode, Diagnostics.Type_instantiation_is_excessively_deep_and_possibly_infinite);
7528
7530
nonTerminating = true;
7529
7531
return t.immediateBaseConstraint = noConstraintType;
7530
7532
}
@@ -9240,18 +9242,6 @@ namespace ts {
9240
9242
return includes;
9241
9243
}
9242
9244
9243
- function isSubtypeOfAny(source: Type, targets: ReadonlyArray<Type>): boolean {
9244
- for (const target of targets) {
9245
- if (source !== target && isTypeSubtypeOf(source, target) && (
9246
- !(getObjectFlags(getTargetType(source)) & ObjectFlags.Class) ||
9247
- !(getObjectFlags(getTargetType(target)) & ObjectFlags.Class) ||
9248
- isTypeDerivedFrom(source, target))) {
9249
- return true;
9250
- }
9251
- }
9252
- return false;
9253
- }
9254
-
9255
9245
function isSetOfLiteralsFromSameEnum(types: ReadonlyArray<Type>): boolean {
9256
9246
const first = types[0];
9257
9247
if (first.flags & TypeFlags.EnumLiteral) {
@@ -9268,17 +9258,40 @@ namespace ts {
9268
9258
return false;
9269
9259
}
9270
9260
9271
- function removeSubtypes(types: Type[]) {
9272
- if (types.length === 0 || isSetOfLiteralsFromSameEnum(types)) {
9273
- return;
9261
+ function removeSubtypes(types: Type[]): boolean {
9262
+ const len = types.length;
9263
+ if (len === 0 || isSetOfLiteralsFromSameEnum(types)) {
9264
+ return true;
9274
9265
}
9275
- let i = types.length;
9266
+ let i = len;
9267
+ let count = 0;
9276
9268
while (i > 0) {
9277
9269
i--;
9278
- if (isSubtypeOfAny(types[i], types)) {
9279
- orderedRemoveItemAt(types, i);
9270
+ const source = types[i];
9271
+ for (const target of types) {
9272
+ if (source !== target) {
9273
+ if (count === 10000) {
9274
+ // After 10000 subtype checks we estimate the remaining amount of work by assuming the
9275
+ // same ratio of checks to removals. If the estimated number of remaining type checks is
9276
+ // greater than 1000000 we deem the union type too complex to represent.
9277
+ const estimatedCount = (count / (len - i)) * len;
9278
+ if (estimatedCount > 1000000) {
9279
+ error(currentNode, Diagnostics.Expression_produces_a_union_type_that_is_too_complex_to_represent);
9280
+ return false;
9281
+ }
9282
+ }
9283
+ count++;
9284
+ if (isTypeSubtypeOf(source, target) && (
9285
+ !(getObjectFlags(getTargetType(source)) & ObjectFlags.Class) ||
9286
+ !(getObjectFlags(getTargetType(target)) & ObjectFlags.Class) ||
9287
+ isTypeDerivedFrom(source, target))) {
9288
+ orderedRemoveItemAt(types, i);
9289
+ break;
9290
+ }
9291
+ }
9280
9292
}
9281
9293
}
9294
+ return true;
9282
9295
}
9283
9296
9284
9297
function removeRedundantLiteralTypes(types: Type[], includes: TypeFlags) {
@@ -9325,7 +9338,9 @@ namespace ts {
9325
9338
}
9326
9339
break;
9327
9340
case UnionReduction.Subtype:
9328
- removeSubtypes(typeSet);
9341
+ if (!removeSubtypes(typeSet)) {
9342
+ return errorType;
9343
+ }
9329
9344
break;
9330
9345
}
9331
9346
if (typeSet.length === 0) {
@@ -10957,6 +10972,7 @@ namespace ts {
10957
10972
// We have reached 50 recursive type instantiations and there is a very high likelyhood we're dealing
10958
10973
// with a combination of infinite generic types that perpetually generate new type identities. We stop
10959
10974
// the recursion here by yielding the error type.
10975
+ error(currentNode, Diagnostics.Type_instantiation_is_excessively_deep_and_possibly_infinite);
10960
10976
return errorType;
10961
10977
}
10962
10978
instantiationDepth++;
@@ -23063,7 +23079,7 @@ namespace ts {
23063
23079
return instantiateTypeWithSingleGenericCallSignature(node, uninstantiatedType, checkMode);
23064
23080
}
23065
23081
23066
- function instantiateTypeWithSingleGenericCallSignature(node: Expression | MethodDeclaration, type: Type, checkMode?: CheckMode) {
23082
+ function instantiateTypeWithSingleGenericCallSignature(node: Expression | MethodDeclaration | QualifiedName , type: Type, checkMode?: CheckMode) {
23067
23083
if (checkMode === CheckMode.Inferential) {
23068
23084
const signature = getSingleCallSignature(type);
23069
23085
if (signature && signature.typeParameters) {
@@ -23133,15 +23149,10 @@ namespace ts {
23133
23149
// have the wildcard function type; this form of type check is used during overload resolution to exclude
23134
23150
// contextually typed function and arrow expressions in the initial phase.
23135
23151
function checkExpression(node: Expression | QualifiedName, checkMode?: CheckMode, forceTuple?: boolean): Type {
23136
- let type: Type;
23137
- if (node.kind === SyntaxKind.QualifiedName) {
23138
- type = checkQualifiedName(<QualifiedName>node);
23139
- }
23140
- else {
23141
- const uninstantiatedType = checkExpressionWorker(node, checkMode, forceTuple);
23142
- type = instantiateTypeWithSingleGenericCallSignature(node, uninstantiatedType, checkMode);
23143
- }
23144
-
23152
+ const saveCurrentNode = currentNode;
23153
+ currentNode = node;
23154
+ const uninstantiatedType = checkExpressionWorker(node, checkMode, forceTuple);
23155
+ const type = instantiateTypeWithSingleGenericCallSignature(node, uninstantiatedType, checkMode);
23145
23156
if (isConstEnumObjectType(type)) {
23146
23157
// enum object type for const enums are only permitted in:
23147
23158
// - 'left' in property access
@@ -23157,6 +23168,7 @@ namespace ts {
23157
23168
error(node, Diagnostics.const_enums_can_only_be_used_in_property_or_index_access_expressions_or_the_right_hand_side_of_an_import_declaration_or_export_assignment_or_type_query);
23158
23169
}
23159
23170
}
23171
+ currentNode = saveCurrentNode;
23160
23172
return type;
23161
23173
}
23162
23174
@@ -23168,7 +23180,7 @@ namespace ts {
23168
23180
return checkExpression(node.expression, checkMode);
23169
23181
}
23170
23182
23171
- function checkExpressionWorker(node: Expression, checkMode: CheckMode | undefined, forceTuple?: boolean): Type {
23183
+ function checkExpressionWorker(node: Expression | QualifiedName , checkMode: CheckMode | undefined, forceTuple?: boolean): Type {
23172
23184
switch (node.kind) {
23173
23185
case SyntaxKind.Identifier:
23174
23186
return checkIdentifier(<Identifier>node);
@@ -23201,6 +23213,8 @@ namespace ts {
23201
23213
return checkObjectLiteral(<ObjectLiteralExpression>node, checkMode);
23202
23214
case SyntaxKind.PropertyAccessExpression:
23203
23215
return checkPropertyAccessExpression(<PropertyAccessExpression>node);
23216
+ case SyntaxKind.QualifiedName:
23217
+ return checkQualifiedName(<QualifiedName>node);
23204
23218
case SyntaxKind.ElementAccessExpression:
23205
23219
return checkIndexedAccess(<ElementAccessExpression>node);
23206
23220
case SyntaxKind.CallExpression:
@@ -27882,10 +27896,15 @@ namespace ts {
27882
27896
}
27883
27897
27884
27898
function checkSourceElement(node: Node | undefined): void {
27885
- if (!node) {
27886
- return;
27899
+ if (node) {
27900
+ const saveCurrentNode = currentNode;
27901
+ currentNode = node;
27902
+ checkSourceElementWorker(node);
27903
+ currentNode = saveCurrentNode;
27887
27904
}
27905
+ }
27888
27906
27907
+ function checkSourceElementWorker(node: Node): void {
27889
27908
if (isInJSFile(node)) {
27890
27909
forEach((node as JSDocContainer).jsDoc, ({ tags }) => forEach(tags, checkSourceElement));
27891
27910
}
@@ -28143,32 +28162,36 @@ namespace ts {
28143
28162
28144
28163
function checkDeferredNodes(context: SourceFile) {
28145
28164
const links = getNodeLinks(context);
28146
- if (! links.deferredNodes) {
28147
- return ;
28165
+ if (links.deferredNodes) {
28166
+ links.deferredNodes.forEach(checkDeferredNode) ;
28148
28167
}
28149
- links.deferredNodes.forEach(node => {
28150
- switch (node.kind) {
28151
- case SyntaxKind.FunctionExpression:
28152
- case SyntaxKind.ArrowFunction:
28153
- case SyntaxKind.MethodDeclaration:
28154
- case SyntaxKind.MethodSignature:
28155
- checkFunctionExpressionOrObjectLiteralMethodDeferred(<FunctionExpression>node);
28156
- break;
28157
- case SyntaxKind.GetAccessor:
28158
- case SyntaxKind.SetAccessor:
28159
- checkAccessorDeclaration(<AccessorDeclaration>node);
28160
- break;
28161
- case SyntaxKind.ClassExpression:
28162
- checkClassExpressionDeferred(<ClassExpression>node);
28163
- break;
28164
- case SyntaxKind.JsxSelfClosingElement:
28165
- checkJsxSelfClosingElementDeferred(<JsxSelfClosingElement>node);
28166
- break;
28167
- case SyntaxKind.JsxElement:
28168
- checkJsxElementDeferred(<JsxElement>node);
28169
- break;
28170
- }
28171
- });
28168
+ }
28169
+
28170
+ function checkDeferredNode(node: Node) {
28171
+ const saveCurrentNode = currentNode;
28172
+ currentNode = node;
28173
+ switch (node.kind) {
28174
+ case SyntaxKind.FunctionExpression:
28175
+ case SyntaxKind.ArrowFunction:
28176
+ case SyntaxKind.MethodDeclaration:
28177
+ case SyntaxKind.MethodSignature:
28178
+ checkFunctionExpressionOrObjectLiteralMethodDeferred(<FunctionExpression>node);
28179
+ break;
28180
+ case SyntaxKind.GetAccessor:
28181
+ case SyntaxKind.SetAccessor:
28182
+ checkAccessorDeclaration(<AccessorDeclaration>node);
28183
+ break;
28184
+ case SyntaxKind.ClassExpression:
28185
+ checkClassExpressionDeferred(<ClassExpression>node);
28186
+ break;
28187
+ case SyntaxKind.JsxSelfClosingElement:
28188
+ checkJsxSelfClosingElementDeferred(<JsxSelfClosingElement>node);
28189
+ break;
28190
+ case SyntaxKind.JsxElement:
28191
+ checkJsxElementDeferred(<JsxElement>node);
28192
+ break;
28193
+ }
28194
+ currentNode = saveCurrentNode;
28172
28195
}
28173
28196
28174
28197
function checkSourceFile(node: SourceFile) {
0 commit comments