Skip to content

Commit 309ae22

Browse files
committed
Cache unnormalized intersection types
1 parent 41a3f83 commit 309ae22

File tree

1 file changed

+33
-24
lines changed

1 file changed

+33
-24
lines changed

src/compiler/checker.ts

Lines changed: 33 additions & 24 deletions
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>();
@@ -9838,6 +9838,15 @@ namespace ts {
98389838
return true;
98399839
}
98409840

9841+
function createIntersectionType(types: Type[], aliasSymbol?: Symbol, aliasTypeArguments?: ReadonlyArray<Type>) {
9842+
const result = <IntersectionType>createType(TypeFlags.Intersection);
9843+
result.objectFlags = getPropagatingFlagsOfTypes(types, /*excludeKinds*/ TypeFlags.Nullable);
9844+
result.types = types;
9845+
result.aliasSymbol = aliasSymbol; // See comment in `getUnionTypeFromSortedList`.
9846+
result.aliasTypeArguments = aliasTypeArguments;
9847+
return result;
9848+
}
9849+
98419850
// We normalize combinations of intersection and union types based on the distributive property of the '&'
98429851
// operator. Specifically, because X & (A | B) is equivalent to X & A | X & B, we can transform intersection
98439852
// types with union type constituents into equivalent union types with intersection type constituents and
@@ -9875,31 +9884,31 @@ namespace ts {
98759884
if (typeSet.length === 1) {
98769885
return typeSet[0];
98779886
}
9878-
if (includes & TypeFlags.Union) {
9879-
if (intersectUnionsOfPrimitiveTypes(typeSet)) {
9880-
// When the intersection creates a reduced set (which might mean that *all* union types have
9881-
// disappeared), we restart the operation to get a new set of combined flags. Once we have
9882-
// reduced we'll never reduce again, so this occurs at most once.
9883-
return getIntersectionType(typeSet, aliasSymbol, aliasTypeArguments);
9884-
}
9885-
// We are attempting to construct a type of the form X & (A | B) & Y. Transform this into a type of
9886-
// the form X & A & Y | X & B & Y and recursively reduce until no union type constituents remain.
9887-
const unionIndex = findIndex(typeSet, t => (t.flags & TypeFlags.Union) !== 0);
9888-
const unionType = <UnionType>typeSet[unionIndex];
9889-
return getUnionType(map(unionType.types, t => getIntersectionType(replaceElement(typeSet, unionIndex, t))),
9890-
UnionReduction.Literal, aliasSymbol, aliasTypeArguments);
9891-
}
98929887
const id = getTypeListId(typeSet);
9893-
let type = intersectionTypes.get(id);
9894-
if (!type) {
9895-
type = <IntersectionType>createType(TypeFlags.Intersection);
9896-
intersectionTypes.set(id, type);
9897-
type.objectFlags = getPropagatingFlagsOfTypes(typeSet, /*excludeKinds*/ TypeFlags.Nullable);
9898-
type.types = typeSet;
9899-
type.aliasSymbol = aliasSymbol; // See comment in `getUnionTypeFromSortedList`.
9900-
type.aliasTypeArguments = aliasTypeArguments;
9888+
let result = intersectionTypes.get(id);
9889+
if (!result) {
9890+
if (includes & TypeFlags.Union) {
9891+
if (intersectUnionsOfPrimitiveTypes(typeSet)) {
9892+
// When the intersection creates a reduced set (which might mean that *all* union types have
9893+
// disappeared), we restart the operation to get a new set of combined flags. Once we have
9894+
// reduced we'll never reduce again, so this occurs at most once.
9895+
result = getIntersectionType(typeSet, aliasSymbol, aliasTypeArguments);
9896+
}
9897+
else {
9898+
// We are attempting to construct a type of the form X & (A | B) & Y. Transform this into a type of
9899+
// the form X & A & Y | X & B & Y and recursively reduce until no union type constituents remain.
9900+
const unionIndex = findIndex(typeSet, t => (t.flags & TypeFlags.Union) !== 0);
9901+
const unionType = <UnionType>typeSet[unionIndex];
9902+
result = getUnionType(map(unionType.types, t => getIntersectionType(replaceElement(typeSet, unionIndex, t))),
9903+
UnionReduction.Literal, aliasSymbol, aliasTypeArguments);
9904+
}
9905+
}
9906+
else {
9907+
result = createIntersectionType(typeSet, aliasSymbol, aliasTypeArguments);
9908+
}
9909+
intersectionTypes.set(id, result);
99019910
}
9902-
return type;
9911+
return result;
99039912
}
99049913

99059914
function getTypeFromIntersectionTypeNode(node: IntersectionTypeNode): Type {

0 commit comments

Comments
 (0)