From 18588104dbd359e54eb4501988139554f58e56fc Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 26 Jun 2015 09:47:58 -0700 Subject: [PATCH] Preserve order in intersection types --- src/compiler/checker.ts | 76 ++++++++++++++++++++--------------------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 32e00af577d..186e35ccfe3 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1539,8 +1539,8 @@ namespace ts { else if (type.flags & TypeFlags.Tuple) { writeTupleType(type); } - else if (type.flags & (TypeFlags.Union | TypeFlags.Intersection)) { - writeUnionOrIntersectionType(type, flags); + else if (type.flags & TypeFlags.UnionOrIntersection) { + writeUnionOrIntersectionType(type, flags); } else if (type.flags & TypeFlags.Anonymous) { writeAnonymousType(type, flags); @@ -3143,7 +3143,7 @@ namespace ts { resolveUnionTypeMembers(type); } else if (type.flags & TypeFlags.Intersection) { - resolveIntersectionTypeMembers(type); + resolveIntersectionTypeMembers(type); } else { resolveTypeReferenceMembers(type); @@ -3299,7 +3299,7 @@ namespace ts { return getPropertyOfObjectType(globalObjectType, name); } if (type.flags & TypeFlags.UnionOrIntersection) { - return getPropertyOfUnionOrIntersectionType(type, name); + return getPropertyOfUnionOrIntersectionType(type, name); } return undefined; } @@ -3864,28 +3864,25 @@ namespace ts { return links.resolvedType; } - function addTypeToSortedSet(sortedSet: Type[], type: Type, typeKind: TypeFlags) { + function addTypeToSet(typeSet: Type[], type: Type, typeKind: TypeFlags) { if (type.flags & typeKind) { - addTypesToSortedSet(sortedSet, (type).types, typeKind); + addTypesToSet(typeSet, (type).types, typeKind); } - else { - let i = 0; - let id = type.id; - while (i < sortedSet.length && sortedSet[i].id < id) { - i++; - } - if (i === sortedSet.length || sortedSet[i].id !== id) { - sortedSet.splice(i, 0, type); - } + else if (!contains(typeSet, type)) { + typeSet.push(type); } } - function addTypesToSortedSet(sortedTypes: Type[], types: Type[], typeKind: TypeFlags) { + function addTypesToSet(typeSet: Type[], types: Type[], typeKind: TypeFlags) { for (let type of types) { - addTypeToSortedSet(sortedTypes, type, typeKind); + addTypeToSet(typeSet, type, typeKind); } } + function compareTypeIds(type1: Type, type2: Type): number { + return type1.id - type2.id; + } + function isSubtypeOfAny(candidate: Type, types: Type[]): boolean { for (let type of types) { if (candidate !== type && isTypeSubtypeOf(candidate, type)) { @@ -3932,26 +3929,27 @@ namespace ts { if (types.length === 0) { return emptyObjectType; } - let sortedTypes: Type[] = []; - addTypesToSortedSet(sortedTypes, types, TypeFlags.Union); + let typeSet: Type[] = []; + addTypesToSet(typeSet, types, TypeFlags.Union); + typeSet.sort(compareTypeIds); if (noSubtypeReduction) { - if (containsTypeAny(sortedTypes)) { + if (containsTypeAny(typeSet)) { return anyType; } - removeAllButLast(sortedTypes, undefinedType); - removeAllButLast(sortedTypes, nullType); + removeAllButLast(typeSet, undefinedType); + removeAllButLast(typeSet, nullType); } else { - removeSubtypes(sortedTypes); + removeSubtypes(typeSet); } - if (sortedTypes.length === 1) { - return sortedTypes[0]; + if (typeSet.length === 1) { + return typeSet[0]; } - let id = getTypeListId(sortedTypes); + let id = getTypeListId(typeSet); let type = unionTypes[id]; if (!type) { - type = unionTypes[id] = createObjectType(TypeFlags.Union | getWideningFlagsOfTypes(sortedTypes)); - type.types = sortedTypes; + type = unionTypes[id] = createObjectType(TypeFlags.Union | getWideningFlagsOfTypes(typeSet)); + type.types = typeSet; type.reducedType = noSubtypeReduction ? undefined : type; } return type; @@ -3986,20 +3984,22 @@ namespace ts { // We do not perform supertype reduction on intersection types. Intersection types are created only by the & // type operator and we can't reduce those because we want to support recursive intersection types. For example, // a type alias of the form "type List = T & { next: List }" cannot be reduced during its declaration. + // Also, unlike union types, the order of the constituent types is preserved in order that overload resolution + // for intersections of types with signatues can be deterministic. function getIntersectionType(types: Type[]): Type { - let sortedTypes: Type[] = []; - addTypesToSortedSet(sortedTypes, types, TypeFlags.Intersection); - if (containsTypeAny(sortedTypes)) { + let typeSet: Type[] = []; + addTypesToSet(typeSet, types, TypeFlags.Intersection); + if (containsTypeAny(typeSet)) { return anyType; } - if (sortedTypes.length === 1) { - return sortedTypes[0]; + if (typeSet.length === 1) { + return typeSet[0]; } - let id = getTypeListId(sortedTypes); + let id = getTypeListId(typeSet); let type = intersectionTypes[id]; if (!type) { - type = intersectionTypes[id] = createObjectType(TypeFlags.Intersection | getWideningFlagsOfTypes(sortedTypes)); - type.types = sortedTypes; + type = intersectionTypes[id] = createObjectType(TypeFlags.Intersection | getWideningFlagsOfTypes(typeSet)); + type.types = typeSet; } return type; } @@ -8128,7 +8128,7 @@ namespace ts { return true; } if (type.flags & TypeFlags.UnionOrIntersection) { - let types = (type).types; + let types = (type).types; for (let current of types) { if (current.flags & kind) { return true; @@ -8145,7 +8145,7 @@ namespace ts { return true; } if (type.flags & TypeFlags.UnionOrIntersection) { - let types = (type).types; + let types = (type).types; for (let current of types) { if (!(current.flags & kind)) { return false;