Skip to content

Commit 3745694

Browse files
authored
Merge pull request #31476 from microsoft/cacheUnnormalizedIntersections
Cache unnormalized intersection types
2 parents 07d850c + 2c34672 commit 3745694

File tree

1 file changed

+33
-24
lines changed

1 file changed

+33
-24
lines changed

src/compiler/checker.ts

+33-24
Original file line numberDiff line numberDiff line change
@@ -391,7 +391,7 @@ namespace ts {
391391

392392
const tupleTypes = createMap<GenericType>();
393393
const unionTypes = createMap<UnionType>();
394-
const intersectionTypes = createMap<IntersectionType>();
394+
const intersectionTypes = createMap<Type>();
395395
const literalTypes = createMap<LiteralType>();
396396
const indexedAccessTypes = createMap<IndexedAccessType>();
397397
const substitutionTypes = createMap<SubstitutionType>();
@@ -9844,6 +9844,15 @@ namespace ts {
98449844
return true;
98459845
}
98469846

9847+
function createIntersectionType(types: Type[], aliasSymbol?: Symbol, aliasTypeArguments?: ReadonlyArray<Type>) {
9848+
const result = <IntersectionType>createType(TypeFlags.Intersection);
9849+
result.objectFlags = getPropagatingFlagsOfTypes(types, /*excludeKinds*/ TypeFlags.Nullable);
9850+
result.types = types;
9851+
result.aliasSymbol = aliasSymbol; // See comment in `getUnionTypeFromSortedList`.
9852+
result.aliasTypeArguments = aliasTypeArguments;
9853+
return result;
9854+
}
9855+
98479856
// We normalize combinations of intersection and union types based on the distributive property of the '&'
98489857
// operator. Specifically, because X & (A | B) is equivalent to X & A | X & B, we can transform intersection
98499858
// types with union type constituents into equivalent union types with intersection type constituents and
@@ -9881,31 +9890,31 @@ namespace ts {
98819890
if (typeSet.length === 1) {
98829891
return typeSet[0];
98839892
}
9884-
if (includes & TypeFlags.Union) {
9885-
if (intersectUnionsOfPrimitiveTypes(typeSet)) {
9886-
// When the intersection creates a reduced set (which might mean that *all* union types have
9887-
// disappeared), we restart the operation to get a new set of combined flags. Once we have
9888-
// reduced we'll never reduce again, so this occurs at most once.
9889-
return getIntersectionType(typeSet, aliasSymbol, aliasTypeArguments);
9890-
}
9891-
// We are attempting to construct a type of the form X & (A | B) & Y. Transform this into a type of
9892-
// the form X & A & Y | X & B & Y and recursively reduce until no union type constituents remain.
9893-
const unionIndex = findIndex(typeSet, t => (t.flags & TypeFlags.Union) !== 0);
9894-
const unionType = <UnionType>typeSet[unionIndex];
9895-
return getUnionType(map(unionType.types, t => getIntersectionType(replaceElement(typeSet, unionIndex, t))),
9896-
UnionReduction.Literal, aliasSymbol, aliasTypeArguments);
9897-
}
98989893
const id = getTypeListId(typeSet);
9899-
let type = intersectionTypes.get(id);
9900-
if (!type) {
9901-
type = <IntersectionType>createType(TypeFlags.Intersection);
9902-
intersectionTypes.set(id, type);
9903-
type.objectFlags = getPropagatingFlagsOfTypes(typeSet, /*excludeKinds*/ TypeFlags.Nullable);
9904-
type.types = typeSet;
9905-
type.aliasSymbol = aliasSymbol; // See comment in `getUnionTypeFromSortedList`.
9906-
type.aliasTypeArguments = aliasTypeArguments;
9894+
let result = intersectionTypes.get(id);
9895+
if (!result) {
9896+
if (includes & TypeFlags.Union) {
9897+
if (intersectUnionsOfPrimitiveTypes(typeSet)) {
9898+
// When the intersection creates a reduced set (which might mean that *all* union types have
9899+
// disappeared), we restart the operation to get a new set of combined flags. Once we have
9900+
// reduced we'll never reduce again, so this occurs at most once.
9901+
result = getIntersectionType(typeSet, aliasSymbol, aliasTypeArguments);
9902+
}
9903+
else {
9904+
// We are attempting to construct a type of the form X & (A | B) & Y. Transform this into a type of
9905+
// the form X & A & Y | X & B & Y and recursively reduce until no union type constituents remain.
9906+
const unionIndex = findIndex(typeSet, t => (t.flags & TypeFlags.Union) !== 0);
9907+
const unionType = <UnionType>typeSet[unionIndex];
9908+
result = getUnionType(map(unionType.types, t => getIntersectionType(replaceElement(typeSet, unionIndex, t))),
9909+
UnionReduction.Literal, aliasSymbol, aliasTypeArguments);
9910+
}
9911+
}
9912+
else {
9913+
result = createIntersectionType(typeSet, aliasSymbol, aliasTypeArguments);
9914+
}
9915+
intersectionTypes.set(id, result);
99079916
}
9908-
return type;
9917+
return result;
99099918
}
99109919

99119920
function getTypeFromIntersectionTypeNode(node: IntersectionTypeNode): Type {

0 commit comments

Comments
 (0)