Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Cache unnormalized intersection types
  • Loading branch information
ahejlsberg committed May 20, 2019
1 parent 41a3f83 commit 309ae22
Showing 1 changed file with 33 additions and 24 deletions.
57 changes: 33 additions & 24 deletions src/compiler/checker.ts
Expand Up @@ -391,7 +391,7 @@ namespace ts {

const tupleTypes = createMap<GenericType>();
const unionTypes = createMap<UnionType>();
const intersectionTypes = createMap<IntersectionType>();
const intersectionTypes = createMap<Type>();
const literalTypes = createMap<LiteralType>();
const indexedAccessTypes = createMap<IndexedAccessType>();
const substitutionTypes = createMap<SubstitutionType>();
Expand Down Expand Up @@ -9838,6 +9838,15 @@ namespace ts {
return true;
}

function createIntersectionType(types: Type[], aliasSymbol?: Symbol, aliasTypeArguments?: ReadonlyArray<Type>) {
const result = <IntersectionType>createType(TypeFlags.Intersection);
result.objectFlags = getPropagatingFlagsOfTypes(types, /*excludeKinds*/ TypeFlags.Nullable);
result.types = types;
result.aliasSymbol = aliasSymbol; // See comment in `getUnionTypeFromSortedList`.
result.aliasTypeArguments = aliasTypeArguments;
return result;
}

// We normalize combinations of intersection and union types based on the distributive property of the '&'
// operator. Specifically, because X & (A | B) is equivalent to X & A | X & B, we can transform intersection
// types with union type constituents into equivalent union types with intersection type constituents and
Expand Down Expand Up @@ -9875,31 +9884,31 @@ namespace ts {
if (typeSet.length === 1) {
return typeSet[0];
}
if (includes & TypeFlags.Union) {
if (intersectUnionsOfPrimitiveTypes(typeSet)) {
// When the intersection creates a reduced set (which might mean that *all* union types have
// disappeared), we restart the operation to get a new set of combined flags. Once we have
// reduced we'll never reduce again, so this occurs at most once.
return getIntersectionType(typeSet, aliasSymbol, aliasTypeArguments);
}
// We are attempting to construct a type of the form X & (A | B) & Y. Transform this into a type of
// the form X & A & Y | X & B & Y and recursively reduce until no union type constituents remain.
const unionIndex = findIndex(typeSet, t => (t.flags & TypeFlags.Union) !== 0);
const unionType = <UnionType>typeSet[unionIndex];
return getUnionType(map(unionType.types, t => getIntersectionType(replaceElement(typeSet, unionIndex, t))),
UnionReduction.Literal, aliasSymbol, aliasTypeArguments);
}
const id = getTypeListId(typeSet);
let type = intersectionTypes.get(id);
if (!type) {
type = <IntersectionType>createType(TypeFlags.Intersection);
intersectionTypes.set(id, type);
type.objectFlags = getPropagatingFlagsOfTypes(typeSet, /*excludeKinds*/ TypeFlags.Nullable);
type.types = typeSet;
type.aliasSymbol = aliasSymbol; // See comment in `getUnionTypeFromSortedList`.
type.aliasTypeArguments = aliasTypeArguments;
let result = intersectionTypes.get(id);
if (!result) {
if (includes & TypeFlags.Union) {
if (intersectUnionsOfPrimitiveTypes(typeSet)) {
// When the intersection creates a reduced set (which might mean that *all* union types have
// disappeared), we restart the operation to get a new set of combined flags. Once we have
// reduced we'll never reduce again, so this occurs at most once.
result = getIntersectionType(typeSet, aliasSymbol, aliasTypeArguments);
}
else {
// We are attempting to construct a type of the form X & (A | B) & Y. Transform this into a type of
// the form X & A & Y | X & B & Y and recursively reduce until no union type constituents remain.
const unionIndex = findIndex(typeSet, t => (t.flags & TypeFlags.Union) !== 0);
const unionType = <UnionType>typeSet[unionIndex];
result = getUnionType(map(unionType.types, t => getIntersectionType(replaceElement(typeSet, unionIndex, t))),
UnionReduction.Literal, aliasSymbol, aliasTypeArguments);
}
}
else {
result = createIntersectionType(typeSet, aliasSymbol, aliasTypeArguments);
}
intersectionTypes.set(id, result);
}
return type;
return result;
}

function getTypeFromIntersectionTypeNode(node: IntersectionTypeNode): Type {
Expand Down

0 comments on commit 309ae22

Please sign in to comment.