Enforce a size limit in getSpreadType

When a union is spread into a union, the sizes are multiplied,
potentially resulting in an enormous union (especially if there are
repeated spreads).  This check detects cases that used to run out of
memory.

Fixes #40754
This commit is contained in:
Andrew Casey
2020-09-24 14:18:16 -07:00
parent fc03982b73
commit 6650496e85
7 changed files with 974 additions and 2 deletions

View File

@@ -14458,14 +14458,14 @@ namespace ts {
if (merged) {
return getSpreadType(merged, right, symbol, objectFlags, readonly);
}
return mapType(left, t => getSpreadType(t, right, symbol, objectFlags, readonly));
return errorTypeIfTooLarge() ?? mapType(left, t => getSpreadType(t, right, symbol, objectFlags, readonly));
}
if (right.flags & TypeFlags.Union) {
const merged = tryMergeUnionOfObjectTypeAndEmptyObject(right as UnionType, readonly);
if (merged) {
return getSpreadType(left, merged, symbol, objectFlags, readonly);
}
return mapType(right, t => getSpreadType(left, t, symbol, objectFlags, readonly));
return errorTypeIfTooLarge() ?? mapType(right, t => getSpreadType(left, t, symbol, objectFlags, readonly));
}
if (right.flags & (TypeFlags.BooleanLike | TypeFlags.NumberLike | TypeFlags.BigIntLike | TypeFlags.StringLike | TypeFlags.EnumLike | TypeFlags.NonPrimitive | TypeFlags.Index)) {
return left;
@@ -14544,6 +14544,17 @@ namespace ts {
getIndexInfoWithReadonly(numberIndexInfo, readonly));
spread.objectFlags |= ObjectFlags.ObjectLiteral | ObjectFlags.ContainsObjectOrArrayLiteral | ObjectFlags.ContainsSpread | objectFlags;
return spread;
function errorTypeIfTooLarge(): Type | undefined {
if (left.flags & right.flags & TypeFlags.Union) {
const resultSize = (left as UnionType).types.length * (right as UnionType).types.length;
if (resultSize > 100000) {
tracing.instant(tracing.Phase.Check, "getSpreadType_DepthLimit", { leftId: left.id, rightId: right.id });
error(currentNode, Diagnostics.Spread_expression_produces_a_union_type_that_is_too_complex_to_represent);
return errorType;
}
}
}
}
/** We approximate own properties as non-methods plus methods that are inside the object literal */

View File

@@ -3048,6 +3048,10 @@
"category": "Error",
"code": 2795
},
"Spread expression produces a union type that is too complex to represent.": {
"category": "Error",
"code": 2796
},
"Import declaration '{0}' is using private name '{1}'.": {
"category": "Error",