@@ -13310,54 +13310,40 @@ namespace ts {
1331013310 return includes;
1331113311 }
1331213312
13313- function isSetOfLiteralsFromSameEnum(types: readonly Type[]): boolean {
13314- const first = types[0];
13315- if (first.flags & TypeFlags.EnumLiteral) {
13316- const firstEnum = getParentOfSymbol(first.symbol);
13317- for (let i = 1; i < types.length; i++) {
13318- const other = types[i];
13319- if (!(other.flags & TypeFlags.EnumLiteral) || (firstEnum !== getParentOfSymbol(other.symbol))) {
13320- return false;
13321- }
13322- }
13323- return true;
13324- }
13325-
13326- return false;
13327- }
13328-
13329- function removeSubtypes(types: Type[], primitivesOnly: boolean): boolean {
13313+ function removeSubtypes(types: Type[], hasObjectTypes: boolean): boolean {
13314+ // We assume that redundant primitive types have already been removed from the types array and that there
13315+ // are no any and unknown types in the array. Thus, the only possible supertypes for primitive types are empty
13316+ // object types, and if none of those are present we can exclude primitive types from the subtype check.
13317+ const hasEmptyObject = hasObjectTypes && some(types, t => !!(t.flags & TypeFlags.Object) && !isGenericMappedType(t) && isEmptyResolvedType(resolveStructuredTypeMembers(<ObjectType>t)));
1333013318 const len = types.length;
13331- if (len === 0 || isSetOfLiteralsFromSameEnum(types)) {
13332- return true;
13333- }
1333413319 let i = len;
1333513320 let count = 0;
1333613321 while (i > 0) {
1333713322 i--;
1333813323 const source = types[i];
13339- for (const target of types) {
13340- if (source !== target) {
13341- if (count === 100000) {
13342- // After 100000 subtype checks we estimate the remaining amount of work by assuming the
13343- // same ratio of checks per element. If the estimated number of remaining type checks is
13344- // greater than an upper limit we deem the union type too complex to represent. The
13345- // upper limit is 25M for unions of primitives only, and 1M otherwise. This for example
13346- // caps union types at 5000 unique literal types and 1000 unique object types.
13347- const estimatedCount = (count / (len - i)) * len;
13348- if (estimatedCount > (primitivesOnly ? 25000000 : 1000000)) {
13349- tracing.instant(tracing.Phase.CheckTypes, "removeSubtypes_DepthLimit", { typeIds: types.map(t => t.id) });
13350- error(currentNode, Diagnostics.Expression_produces_a_union_type_that_is_too_complex_to_represent);
13351- return false;
13324+ if (hasEmptyObject || source.flags & TypeFlags.StructuredOrInstantiable) {
13325+ for (const target of types) {
13326+ if (source !== target) {
13327+ if (count === 100000) {
13328+ // After 100000 subtype checks we estimate the remaining amount of work by assuming the
13329+ // same ratio of checks per element. If the estimated number of remaining type checks is
13330+ // greater than 1M we deem the union type too complex to represent. This for example
13331+ // caps union types at 1000 unique object types.
13332+ const estimatedCount = (count / (len - i)) * len;
13333+ if (estimatedCount > 1000000) {
13334+ tracing.instant(tracing.Phase.CheckTypes, "removeSubtypes_DepthLimit", { typeIds: types.map(t => t.id) });
13335+ error(currentNode, Diagnostics.Expression_produces_a_union_type_that_is_too_complex_to_represent);
13336+ return false;
13337+ }
13338+ }
13339+ count++;
13340+ if (isTypeRelatedTo(source, target, strictSubtypeRelation) && (
13341+ !(getObjectFlags(getTargetType(source)) & ObjectFlags.Class) ||
13342+ !(getObjectFlags(getTargetType(target)) & ObjectFlags.Class) ||
13343+ isTypeDerivedFrom(source, target))) {
13344+ orderedRemoveItemAt(types, i);
13345+ break;
1335213346 }
13353- }
13354- count++;
13355- if (isTypeRelatedTo(source, target, strictSubtypeRelation) && (
13356- !(getObjectFlags(getTargetType(source)) & ObjectFlags.Class) ||
13357- !(getObjectFlags(getTargetType(target)) & ObjectFlags.Class) ||
13358- isTypeDerivedFrom(source, target))) {
13359- orderedRemoveItemAt(types, i);
13360- break;
1336113347 }
1336213348 }
1336313349 }
@@ -13370,11 +13356,13 @@ namespace ts {
1337013356 while (i > 0) {
1337113357 i--;
1337213358 const t = types[i];
13359+ const flags = t.flags;
1337313360 const remove =
13374- t.flags & TypeFlags.StringLiteral && includes & TypeFlags.String ||
13375- t.flags & TypeFlags.NumberLiteral && includes & TypeFlags.Number ||
13376- t.flags & TypeFlags.BigIntLiteral && includes & TypeFlags.BigInt ||
13377- t.flags & TypeFlags.UniqueESSymbol && includes & TypeFlags.ESSymbol ||
13361+ flags & TypeFlags.StringLiteral && includes & TypeFlags.String ||
13362+ flags & TypeFlags.NumberLiteral && includes & TypeFlags.Number ||
13363+ flags & TypeFlags.BigIntLiteral && includes & TypeFlags.BigInt ||
13364+ flags & TypeFlags.UniqueESSymbol && includes & TypeFlags.ESSymbol ||
13365+ flags & TypeFlags.Undefined && includes & TypeFlags.Void ||
1337813366 isFreshLiteralType(t) && containsType(types, (<LiteralType>t).regularType);
1337913367 if (remove) {
1338013368 orderedRemoveItemAt(types, i);
@@ -13440,20 +13428,18 @@ namespace ts {
1344013428 if (includes & TypeFlags.AnyOrUnknown) {
1344113429 return includes & TypeFlags.Any ? includes & TypeFlags.IncludesWildcard ? wildcardType : anyType : unknownType;
1344213430 }
13443- switch (unionReduction) {
13444- case UnionReduction.Literal:
13445- if (includes & (TypeFlags.Literal | TypeFlags.UniqueESSymbol)) {
13446- removeRedundantLiteralTypes(typeSet, includes);
13447- }
13448- if (includes & TypeFlags.StringLiteral && includes & TypeFlags.TemplateLiteral) {
13449- removeStringLiteralsMatchedByTemplateLiterals(typeSet);
13450- }
13451- break;
13452- case UnionReduction.Subtype:
13453- if (!removeSubtypes(typeSet, !(includes & TypeFlags.IncludesStructuredOrInstantiable))) {
13454- return errorType;
13455- }
13456- break;
13431+ if (unionReduction & (UnionReduction.Literal | UnionReduction.Subtype)) {
13432+ if (includes & (TypeFlags.Literal | TypeFlags.UniqueESSymbol) || includes & TypeFlags.Void && includes & TypeFlags.Undefined) {
13433+ removeRedundantLiteralTypes(typeSet, includes);
13434+ }
13435+ if (includes & TypeFlags.StringLiteral && includes & TypeFlags.TemplateLiteral) {
13436+ removeStringLiteralsMatchedByTemplateLiterals(typeSet);
13437+ }
13438+ }
13439+ if (unionReduction & UnionReduction.Subtype) {
13440+ if (!removeSubtypes(typeSet, !!(includes & TypeFlags.Object))) {
13441+ return errorType;
13442+ }
1345713443 }
1345813444 if (typeSet.length === 0) {
1345913445 return includes & TypeFlags.Null ? includes & TypeFlags.IncludesNonWideningType ? nullType : nullWideningType :
@@ -28985,7 +28971,7 @@ namespace ts {
2898528971 if (returnType.flags & TypeFlags.ESSymbolLike && isSymbolOrSymbolForCall(node)) {
2898628972 return getESSymbolLikeTypeForNode(walkUpParenthesizedExpressions(node.parent));
2898728973 }
28988- if (node.kind === SyntaxKind.CallExpression && node.parent.kind === SyntaxKind.ExpressionStatement &&
28974+ if (node.kind === SyntaxKind.CallExpression && !node.questionDotToken && node.parent.kind === SyntaxKind.ExpressionStatement &&
2898928975 returnType.flags & TypeFlags.Void && getTypePredicateOfSignature(signature)) {
2899028976 if (!isDottedName(node.expression)) {
2899128977 error(node.expression, Diagnostics.Assertions_require_the_call_target_to_be_an_identifier_or_qualified_name);
0 commit comments