@@ -20780,6 +20780,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2078020780 let skipParentCounter = 0; // How many errors should be skipped 'above' in the elaboration pyramid
2078120781 let lastSkippedInfo: [Type, Type] | undefined;
2078220782 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;
2078320786
2078420787 Debug.assert(relation !== identityRelation || !errorNode, "no error reporting in identity checking");
2078520788
@@ -20788,8 +20791,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2078820791 reportIncompatibleStack();
2078920792 }
2079020793 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);
2079120797 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));
2079320802 if (errorOutputContainer) {
2079420803 (errorOutputContainer.errors || (errorOutputContainer.errors = [])).push(diag);
2079520804 }
@@ -21422,6 +21431,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2142221431 // we need to deconstruct unions before intersections (because unions are always at the top),
2142321432 // and we need to handle "each" relations before "some" relations for the same kind of type.
2142421433 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+ }
2142521450 return relation === comparableRelation ?
2142621451 someTypeRelatedToType(source as UnionType, target, reportErrors && !(source.flags & TypeFlags.Primitive), intersectionState) :
2142721452 eachTypeRelatedToType(source as UnionType, target, reportErrors && !(source.flags & TypeFlags.Primitive), intersectionState);
@@ -21673,6 +21698,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2167321698 return entry & RelationComparisonResult.Succeeded ? Ternary.True : Ternary.False;
2167421699 }
2167521700 }
21701+ if (relationCount <= 0) {
21702+ overflow = true;
21703+ return Ternary.False;
21704+ }
2167621705 if (!maybeKeys) {
2167721706 maybeKeys = [];
2167821707 maybeKeysSet = new Set();
@@ -21770,6 +21799,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2177021799 // A false result goes straight into global cache (when something is false under
2177121800 // assumptions it will also be false without assumptions)
2177221801 relation.set(id, (reportErrors ? RelationComparisonResult.Reported : 0) | RelationComparisonResult.Failed | propagatingVarianceFlags);
21802+ relationCount--;
2177321803 resetMaybeStack(/*markAllAsSucceeded*/ false);
2177421804 }
2177521805 return result;
@@ -21779,6 +21809,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2177921809 maybeKeysSet.delete(maybeKeys[i]);
2178021810 if (markAllAsSucceeded) {
2178121811 relation.set(maybeKeys[i], RelationComparisonResult.Succeeded | propagatingVarianceFlags);
21812+ relationCount--;
2178221813 }
2178321814 }
2178421815 maybeCount = maybeStart;
@@ -39768,16 +39799,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3976839799 checkSourceElement(node.argument);
3976939800
3977039801 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);
3978139803 }
3978239804 checkTypeReferenceOrImport(node);
3978339805 }
@@ -45248,25 +45270,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
4524845270 const override = getResolutionModeOverride(node, validForTypeAttributes ? grammarErrorOnNode : undefined);
4524945271 const isImportAttributes = declaration.attributes.token === SyntaxKind.WithKeyword;
4525045272 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- }
4525945273 return; // Other grammar checks do not apply to type-only imports with resolution mode assertions
4526045274 }
4526145275
4526245276 const mode = (moduleKind === ModuleKind.NodeNext) && declaration.moduleSpecifier && getUsageModeForExpression(declaration.moduleSpecifier);
4526345277 if (mode !== ModuleKind.ESNext && moduleKind !== ModuleKind.ESNext) {
4526445278 const message = isImportAttributes
4526545279 ? 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
4526745281 : Diagnostics.Import_attributes_are_only_supported_when_the_module_option_is_set_to_esnext_or_nodenext
4526845282 : 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
4527045284 : Diagnostics.Import_assertions_are_only_supported_when_the_module_option_is_set_to_esnext_or_nodenext;
4527145285 return grammarErrorOnNode(node, message);
4527245286 }
0 commit comments