@@ -20780,6 +20780,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
20780
20780
let skipParentCounter = 0; // How many errors should be skipped 'above' in the elaboration pyramid
20781
20781
let lastSkippedInfo: [Type, Type] | undefined;
20782
20782
let incompatibleStack: DiagnosticAndArguments[] | undefined;
20783
+ // In Node.js, the maximum number of elements in a map is 2^24. We limit the number of entries an invocation
20784
+ // of checkTypeRelatedTo can add to a relation to 1/8th of its remaining capacity.
20785
+ let relationCount = (16_000_000 - relation.size) >> 3;
20783
20786
20784
20787
Debug.assert(relation !== identityRelation || !errorNode, "no error reporting in identity checking");
20785
20788
@@ -20788,8 +20791,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
20788
20791
reportIncompatibleStack();
20789
20792
}
20790
20793
if (overflow) {
20794
+ // Record this relation as having failed such that we don't attempt the overflowing operation again.
20795
+ const id = getRelationKey(source, target, /*intersectionState*/ IntersectionState.None, relation, /*ignoreConstraints*/ false);
20796
+ relation.set(id, RelationComparisonResult.Reported | RelationComparisonResult.Failed);
20791
20797
tracing?.instant(tracing.Phase.CheckTypes, "checkTypeRelatedTo_DepthLimit", { sourceId: source.id, targetId: target.id, depth: sourceDepth, targetDepth });
20792
- const diag = error(errorNode || currentNode, Diagnostics.Excessive_stack_depth_comparing_types_0_and_1, typeToString(source), typeToString(target));
20798
+ const message = relationCount <= 0 ?
20799
+ Diagnostics.Excessive_complexity_comparing_types_0_and_1 :
20800
+ Diagnostics.Excessive_stack_depth_comparing_types_0_and_1;
20801
+ const diag = error(errorNode || currentNode, message, typeToString(source), typeToString(target));
20793
20802
if (errorOutputContainer) {
20794
20803
(errorOutputContainer.errors || (errorOutputContainer.errors = [])).push(diag);
20795
20804
}
@@ -21422,6 +21431,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
21422
21431
// we need to deconstruct unions before intersections (because unions are always at the top),
21423
21432
// and we need to handle "each" relations before "some" relations for the same kind of type.
21424
21433
if (source.flags & TypeFlags.Union) {
21434
+ if (target.flags & TypeFlags.Union) {
21435
+ // Intersections of union types are normalized into unions of intersection types, and such normalized
21436
+ // unions can get very large and expensive to relate. The following fast path checks if the source union
21437
+ // originated in an intersection. If so, and if that intersection contains the target type, then we know
21438
+ // the result to be true (for any two types A and B, A & B is related to both A and B).
21439
+ const sourceOrigin = (source as UnionType).origin;
21440
+ if (sourceOrigin && sourceOrigin.flags & TypeFlags.Intersection && target.aliasSymbol && contains((sourceOrigin as IntersectionType).types, target)) {
21441
+ return Ternary.True;
21442
+ }
21443
+ // Similarly, in unions of unions the we preserve the original list of unions. This original list is often
21444
+ // much shorter than the normalized result, so we scan it in the following fast path.
21445
+ const targetOrigin = (target as UnionType).origin;
21446
+ if (targetOrigin && targetOrigin.flags & TypeFlags.Union && source.aliasSymbol && contains((targetOrigin as UnionType).types, source)) {
21447
+ return Ternary.True;
21448
+ }
21449
+ }
21425
21450
return relation === comparableRelation ?
21426
21451
someTypeRelatedToType(source as UnionType, target, reportErrors && !(source.flags & TypeFlags.Primitive), intersectionState) :
21427
21452
eachTypeRelatedToType(source as UnionType, target, reportErrors && !(source.flags & TypeFlags.Primitive), intersectionState);
@@ -21673,6 +21698,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
21673
21698
return entry & RelationComparisonResult.Succeeded ? Ternary.True : Ternary.False;
21674
21699
}
21675
21700
}
21701
+ if (relationCount <= 0) {
21702
+ overflow = true;
21703
+ return Ternary.False;
21704
+ }
21676
21705
if (!maybeKeys) {
21677
21706
maybeKeys = [];
21678
21707
maybeKeysSet = new Set();
@@ -21770,6 +21799,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
21770
21799
// A false result goes straight into global cache (when something is false under
21771
21800
// assumptions it will also be false without assumptions)
21772
21801
relation.set(id, (reportErrors ? RelationComparisonResult.Reported : 0) | RelationComparisonResult.Failed | propagatingVarianceFlags);
21802
+ relationCount--;
21773
21803
resetMaybeStack(/*markAllAsSucceeded*/ false);
21774
21804
}
21775
21805
return result;
@@ -21779,6 +21809,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
21779
21809
maybeKeysSet.delete(maybeKeys[i]);
21780
21810
if (markAllAsSucceeded) {
21781
21811
relation.set(maybeKeys[i], RelationComparisonResult.Succeeded | propagatingVarianceFlags);
21812
+ relationCount--;
21782
21813
}
21783
21814
}
21784
21815
maybeCount = maybeStart;
@@ -39768,16 +39799,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
39768
39799
checkSourceElement(node.argument);
39769
39800
39770
39801
if (node.attributes) {
39771
- const override = getResolutionModeOverride(node.attributes, grammarErrorOnNode);
39772
- const errorNode = node.attributes;
39773
- if (override && errorNode && getEmitModuleResolutionKind(compilerOptions) !== ModuleResolutionKind.Node16 && getEmitModuleResolutionKind(compilerOptions) !== ModuleResolutionKind.NodeNext) {
39774
- grammarErrorOnNode(
39775
- errorNode,
39776
- node.attributes.token === SyntaxKind.WithKeyword
39777
- ? Diagnostics.The_resolution_mode_attribute_is_only_supported_when_moduleResolution_is_node16_or_nodenext
39778
- : Diagnostics.resolution_mode_assertions_are_only_supported_when_moduleResolution_is_node16_or_nodenext,
39779
- );
39780
- }
39802
+ getResolutionModeOverride(node.attributes, grammarErrorOnNode);
39781
39803
}
39782
39804
checkTypeReferenceOrImport(node);
39783
39805
}
@@ -45248,25 +45270,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
45248
45270
const override = getResolutionModeOverride(node, validForTypeAttributes ? grammarErrorOnNode : undefined);
45249
45271
const isImportAttributes = declaration.attributes.token === SyntaxKind.WithKeyword;
45250
45272
if (validForTypeAttributes && override) {
45251
- if (getEmitModuleResolutionKind(compilerOptions) !== ModuleResolutionKind.Node16 && getEmitModuleResolutionKind(compilerOptions) !== ModuleResolutionKind.NodeNext) {
45252
- return grammarErrorOnNode(
45253
- node,
45254
- isImportAttributes
45255
- ? Diagnostics.The_resolution_mode_attribute_is_only_supported_when_moduleResolution_is_node16_or_nodenext
45256
- : Diagnostics.resolution_mode_assertions_are_only_supported_when_moduleResolution_is_node16_or_nodenext,
45257
- );
45258
- }
45259
45273
return; // Other grammar checks do not apply to type-only imports with resolution mode assertions
45260
45274
}
45261
45275
45262
45276
const mode = (moduleKind === ModuleKind.NodeNext) && declaration.moduleSpecifier && getUsageModeForExpression(declaration.moduleSpecifier);
45263
45277
if (mode !== ModuleKind.ESNext && moduleKind !== ModuleKind.ESNext) {
45264
45278
const message = isImportAttributes
45265
45279
? moduleKind === ModuleKind.NodeNext
45266
- ? Diagnostics.Import_attributes_are_not_allowed_on_statements_that_transpile_to_CommonJS_require_calls
45280
+ ? Diagnostics.Import_attributes_are_not_allowed_on_statements_that_compile_to_CommonJS_require_calls
45267
45281
: Diagnostics.Import_attributes_are_only_supported_when_the_module_option_is_set_to_esnext_or_nodenext
45268
45282
: moduleKind === ModuleKind.NodeNext
45269
- ? Diagnostics.Import_assertions_are_not_allowed_on_statements_that_transpile_to_CommonJS_require_calls
45283
+ ? Diagnostics.Import_assertions_are_not_allowed_on_statements_that_compile_to_CommonJS_require_calls
45270
45284
: Diagnostics.Import_assertions_are_only_supported_when_the_module_option_is_set_to_esnext_or_nodenext;
45271
45285
return grammarErrorOnNode(node, message);
45272
45286
}
0 commit comments