From 79a73bf51029a8b59bc792063827689e05192e55 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 25 Oct 2021 15:05:06 -0700 Subject: [PATCH] Always cache relations involving intersection types --- src/compiler/checker.ts | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 217eb47cfa..ed75651e6e 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -18207,13 +18207,12 @@ namespace ts { let result = Ternary.False; const saveErrorInfo = captureErrorCalculationState(); - // Note that these checks are specifically ordered to produce correct results. In particular, - // we need to deconstruct unions before intersections (because unions are always at the top), - // and we need to handle "each" relations before "some" relations for the same kind of type. - if (source.flags & TypeFlags.UnionOrIntersection || target.flags & TypeFlags.UnionOrIntersection) { - result = getConstituentCount(source) * getConstituentCount(target) >= 4 ? - recursiveTypeRelatedTo(source, target, reportErrors, intersectionState | IntersectionState.UnionIntersectionCheck, recursionFlags) : - structuredTypeRelatedTo(source, target, reportErrors, intersectionState | IntersectionState.UnionIntersectionCheck); + if ((source.flags & TypeFlags.Union || target.flags & TypeFlags.Union) && getConstituentCount(source) * getConstituentCount(target) < 4) { + // We skip caching when source or target is a union with no more than three constituents. + result = structuredTypeRelatedTo(source, target, reportErrors, intersectionState | IntersectionState.UnionIntersectionCheck); + } + else if (source.flags & TypeFlags.UnionOrIntersection || target.flags & TypeFlags.UnionOrIntersection) { + result = recursiveTypeRelatedTo(source, target, reportErrors, intersectionState | IntersectionState.UnionIntersectionCheck, recursionFlags); } if (!result && !(source.flags & TypeFlags.Union) && (source.flags & (TypeFlags.StructuredOrInstantiable) || target.flags & TypeFlags.StructuredOrInstantiable)) { if (result = recursiveTypeRelatedTo(source, target, reportErrors, intersectionState, recursionFlags)) { @@ -18677,17 +18676,17 @@ namespace ts { const maybeStart = maybeCount; maybeKeys[maybeCount] = id; maybeCount++; + const saveExpandingFlags = expandingFlags; if (recursionFlags & RecursionFlags.Source) { sourceStack[sourceDepth] = source; sourceDepth++; + if (!(expandingFlags & ExpandingFlags.Source) && isDeeplyNestedType(source, sourceStack, sourceDepth)) expandingFlags |= ExpandingFlags.Source; } if (recursionFlags & RecursionFlags.Target) { targetStack[targetDepth] = target; targetDepth++; + if (!(expandingFlags & ExpandingFlags.Target) && isDeeplyNestedType(target, targetStack, targetDepth)) expandingFlags |= ExpandingFlags.Target; } - const saveExpandingFlags = expandingFlags; - if (!(expandingFlags & ExpandingFlags.Source) && isDeeplyNestedType(source, sourceStack, sourceDepth)) expandingFlags |= ExpandingFlags.Source; - if (!(expandingFlags & ExpandingFlags.Target) && isDeeplyNestedType(target, targetStack, targetDepth)) expandingFlags |= ExpandingFlags.Target; let originalHandler: typeof outofbandVarianceMarkerHandler; let propagatingVarianceFlags: RelationComparisonResult = 0; if (outofbandVarianceMarkerHandler) { @@ -18713,13 +18712,13 @@ namespace ts { if (outofbandVarianceMarkerHandler) { outofbandVarianceMarkerHandler = originalHandler; } - expandingFlags = saveExpandingFlags; if (recursionFlags & RecursionFlags.Source) { sourceDepth--; } if (recursionFlags & RecursionFlags.Target) { targetDepth--; } + expandingFlags = saveExpandingFlags; if (result) { if (result === Ternary.True || (sourceDepth === 0 && targetDepth === 0)) { if (result === Ternary.True || result === Ternary.Maybe) { @@ -23150,7 +23149,7 @@ namespace ts { } function getConstituentCount(type: Type) { - return type.flags & TypeFlags.UnionOrIntersection ? (type as UnionOrIntersectionType).types.length : 1; + return type.flags & TypeFlags.Union ? (type as UnionType).types.length : 1; } function extractTypesOfKind(type: Type, kind: TypeFlags) {