Skip to content

Commit 9dec535

Browse files
committed
Sort intersections
1 parent 5c92af1 commit 9dec535

1 file changed

Lines changed: 12 additions & 14 deletions

File tree

src/compiler/checker.ts

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16125,7 +16125,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1612516125
}
1612616126

1612716127
function insertType(types: Type[], type: Type): boolean {
16128-
const index = binarySearch(types, type, getTypeId, compareValues);
16128+
// TODO(jakebailey): we already have insertSorted and should use it here (adding the perf optimization?)
16129+
const len = types.length;
16130+
// Perf optimization (measure?); check the last element first as we often insert in order.
16131+
const index = len && type.id > types[len - 1].id ? ~len : binarySearch(types, type, getTypeId, compareValues);
1612916132
if (index < 0) {
1613016133
types.splice(~index, 0, type);
1613116134
return true;
@@ -16147,11 +16150,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1614716150
if (!(getObjectFlags(type) & ObjectFlags.ContainsWideningType)) includes |= TypeFlags.IncludesNonWideningType;
1614816151
}
1614916152
else {
16150-
const len = typeSet.length;
16151-
const index = len && type.id > typeSet[len - 1].id ? ~len : binarySearch(typeSet, type, getTypeId, compareValues);
16152-
if (index < 0) {
16153-
typeSet.splice(~index, 0, type);
16154-
}
16153+
insertType(typeSet, type);
1615516154
}
1615616155
}
1615716156
return includes;
@@ -16439,15 +16438,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1643916438
return links.resolvedType;
1644016439
}
1644116440

16442-
function addTypeToIntersection(typeSet: Map<string, Type>, includes: TypeFlags, type: Type) {
16441+
function addTypeToIntersection(typeSet: Type[], includes: TypeFlags, type: Type) {
1644316442
const flags = type.flags;
1644416443
if (flags & TypeFlags.Intersection) {
1644516444
return addTypesToIntersection(typeSet, includes, (type as IntersectionType).types);
1644616445
}
1644716446
if (isEmptyAnonymousObjectType(type)) {
1644816447
if (!(includes & TypeFlags.IncludesEmptyObject)) {
1644916448
includes |= TypeFlags.IncludesEmptyObject;
16450-
typeSet.set(type.id.toString(), type);
16449+
insertType(typeSet, type);
1645116450
}
1645216451
}
1645316452
else {
@@ -16459,13 +16458,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1645916458
includes |= TypeFlags.IncludesMissingType;
1646016459
type = undefinedType;
1646116460
}
16462-
if (!typeSet.has(type.id.toString())) {
16461+
const inserted = insertType(typeSet, type);
16462+
if (inserted) {
1646316463
if (type.flags & TypeFlags.Unit && includes & TypeFlags.Unit) {
1646416464
// We have seen two distinct unit types which means we should reduce to an
1646516465
// empty intersection. Adding TypeFlags.NonPrimitive causes that to happen.
1646616466
includes |= TypeFlags.NonPrimitive;
1646716467
}
16468-
typeSet.set(type.id.toString(), type);
1646916468
}
1647016469
}
1647116470
includes |= flags & TypeFlags.IncludesMask;
@@ -16475,7 +16474,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1647516474

1647616475
// Add the given types to the given type set. Order is preserved, freshness is removed from literal
1647716476
// types, duplicates are removed, and nested types of the given kind are flattened into the set.
16478-
function addTypesToIntersection(typeSet: Map<string, Type>, includes: TypeFlags, types: readonly Type[]) {
16477+
function addTypesToIntersection(typeSet: Type[], includes: TypeFlags, types: readonly Type[]) {
1647916478
for (const type of types) {
1648016479
includes = addTypeToIntersection(typeSet, includes, getRegularTypeOfLiteralType(type));
1648116480
}
@@ -16618,9 +16617,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1661816617
// Also, unlike union types, the order of the constituent types is preserved in order that overload resolution
1661916618
// for intersections of types with signatures can be deterministic.
1662016619
function getIntersectionType(types: readonly Type[], aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[], noSupertypeReduction?: boolean): Type {
16621-
const typeMembershipMap: Map<string, Type> = new Map();
16622-
const includes = addTypesToIntersection(typeMembershipMap, 0 as TypeFlags, types);
16623-
const typeSet: Type[] = arrayFrom(typeMembershipMap.values());
16620+
const typeSet: Type[] = [];
16621+
const includes = addTypesToIntersection(typeSet, 0 as TypeFlags, types);
1662416622
// An intersection type is considered empty if it contains
1662516623
// the type never, or
1662616624
// more than one unit type or,

0 commit comments

Comments
 (0)