Skip to content

Commit c6fab76

Browse files
committed
Add --stableTypeOrdering for TS7 ordering compat
1 parent 43db4c1 commit c6fab76

8 files changed

Lines changed: 585 additions & 106 deletions

File tree

src/compiler/checker.ts

Lines changed: 466 additions & 23 deletions
Large diffs are not rendered by default.

src/compiler/commandLineParser.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -961,6 +961,15 @@ const commandOptionsWithoutBuild: CommandLineOption[] = [
961961
description: Diagnostics.Built_in_iterators_are_instantiated_with_a_TReturn_type_of_undefined_instead_of_any,
962962
defaultValueDescription: Diagnostics.false_unless_strict_is_set,
963963
},
964+
{
965+
name: "stableTypeOrdering",
966+
type: "boolean",
967+
affectsSemanticDiagnostics: true,
968+
affectsBuildInfo: true,
969+
category: Diagnostics.Type_Checking,
970+
description: Diagnostics.Ensure_types_are_ordered_stably_and_deterministically_across_compilations,
971+
defaultValueDescription: true,
972+
},
964973
{
965974
name: "noImplicitThis",
966975
type: "boolean",

src/compiler/core.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1209,7 +1209,7 @@ export function binarySearchKey<T, U>(array: readonly T[], key: U, keySelector:
12091209
while (low <= high) {
12101210
const middle = low + ((high - low) >> 1);
12111211
const midKey = keySelector(array[middle], middle);
1212-
switch (keyComparer(midKey, key)) {
1212+
switch (Math.sign(keyComparer(midKey, key))) {
12131213
case Comparison.LessThan:
12141214
low = middle + 1;
12151215
break;
@@ -1967,9 +1967,11 @@ export function equateStringsCaseSensitive(a: string, b: string): boolean {
19671967
return equateValues(a, b);
19681968
}
19691969

1970-
function compareComparableValues(a: string | undefined, b: string | undefined): Comparison;
1971-
function compareComparableValues(a: number | undefined, b: number | undefined): Comparison;
1972-
function compareComparableValues(a: string | number | undefined, b: string | number | undefined) {
1970+
/** @internal */
1971+
export function compareComparableValues(a: string | undefined, b: string | undefined): Comparison;
1972+
/** @internal */
1973+
export function compareComparableValues(a: number | undefined, b: number | undefined): Comparison;
1974+
export function compareComparableValues(a: string | number | undefined, b: string | number | undefined) {
19731975
return a === b ? Comparison.EqualTo :
19741976
a === undefined ? Comparison.LessThan :
19751977
b === undefined ? Comparison.GreaterThan :

src/compiler/diagnosticMessages.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6589,6 +6589,10 @@
65896589
"category": "Message",
65906590
"code": 6808
65916591
},
6592+
"Ensure types are ordered stably and deterministically across compilations.": {
6593+
"category": "Message",
6594+
"code": 6809
6595+
},
65926596

65936597
"one of:": {
65946598
"category": "Message",

src/compiler/types.ts

Lines changed: 42 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -6320,42 +6320,49 @@ export interface SerializedTypeEntry {
63206320
trackedSymbols: readonly TrackedSymbol[] | undefined;
63216321
}
63226322

6323+
// Note that for types of different kinds, the numeric values of TypeFlags determine the order
6324+
// computed by the CompareTypes function and therefore the order of constituent types in union types.
6325+
// Since union type processing often bails out early when a result is known, it is important to order
6326+
// TypeFlags in increasing order of potential type complexity. In particular, indexed access and
6327+
// conditional types should sort last as those types are potentially recursive and possibly infinite.
6328+
63236329
// dprint-ignore
63246330
export const enum TypeFlags {
63256331
Any = 1 << 0,
63266332
Unknown = 1 << 1,
6327-
String = 1 << 2,
6328-
Number = 1 << 3,
6329-
Boolean = 1 << 4,
6330-
Enum = 1 << 5, // Numeric computed enum member value
6331-
BigInt = 1 << 6,
6332-
StringLiteral = 1 << 7,
6333-
NumberLiteral = 1 << 8,
6334-
BooleanLiteral = 1 << 9,
6335-
EnumLiteral = 1 << 10, // Always combined with StringLiteral, NumberLiteral, or Union
6336-
BigIntLiteral = 1 << 11,
6337-
ESSymbol = 1 << 12, // Type of symbol primitive introduced in ES6
6338-
UniqueESSymbol = 1 << 13, // unique symbol
6339-
Void = 1 << 14,
6340-
Undefined = 1 << 15,
6341-
Null = 1 << 16,
6342-
Never = 1 << 17, // Never type
6343-
TypeParameter = 1 << 18, // Type parameter
6344-
Object = 1 << 19, // Object type
6345-
Union = 1 << 20, // Union (T | U)
6346-
Intersection = 1 << 21, // Intersection (T & U)
6347-
Index = 1 << 22, // keyof T
6348-
IndexedAccess = 1 << 23, // T[K]
6349-
Conditional = 1 << 24, // T extends U ? X : Y
6350-
Substitution = 1 << 25, // Type parameter substitution
6351-
NonPrimitive = 1 << 26, // intrinsic object type
6352-
TemplateLiteral = 1 << 27, // Template literal type
6353-
StringMapping = 1 << 28, // Uppercase/Lowercase type
6333+
Undefined = 1 << 2,
6334+
Null = 1 << 3,
6335+
Void = 1 << 4,
6336+
String = 1 << 5,
6337+
Number = 1 << 6,
6338+
BigInt = 1 << 7,
6339+
Boolean = 1 << 8,
6340+
ESSymbol = 1 << 9, // Type of symbol primitive introduced in ES6
6341+
StringLiteral = 1 << 10,
6342+
NumberLiteral = 1 << 11,
6343+
BigIntLiteral = 1 << 12,
6344+
BooleanLiteral = 1 << 13,
6345+
UniqueESSymbol = 1 << 14, // unique symbol
6346+
EnumLiteral = 1 << 15, // Always combined with StringLiteral, NumberLiteral, or Union
6347+
Enum = 1 << 16, // Numeric computed enum member value (must be right after EnumLiteral, see getSortOrderFlags)
6348+
NonPrimitive = 1 << 17, // intrinsic object type
6349+
Never = 1 << 18, // Never type
6350+
TypeParameter = 1 << 19, // Type parameter
6351+
Object = 1 << 20, // Object type
6352+
Index = 1 << 21, // keyof T
6353+
TemplateLiteral = 1 << 22, // Template literal type
6354+
StringMapping = 1 << 23, // Uppercase/Lowercase type
6355+
Substitution = 1 << 24, // Type parameter substitution
6356+
IndexedAccess = 1 << 25, // T[K]
6357+
Conditional = 1 << 26, // T extends U ? X : Y
6358+
Union = 1 << 27, // Union (T | U)
6359+
Intersection = 1 << 28, // Intersection (T & U)
63546360
/** @internal */
63556361
Reserved1 = 1 << 29, // Used by union/intersection type construction
63566362
/** @internal */
63576363
Reserved2 = 1 << 30, // Used by union/intersection type construction
6358-
6364+
/** @internal */
6365+
Reserved3 = 1 << 31,
63596366
/** @internal */
63606367
AnyOrUnknown = Any | Unknown,
63616368
/** @internal */
@@ -6539,14 +6546,16 @@ export const enum ObjectFlags {
65396546
PropagatingFlags = ContainsWideningType | ContainsObjectOrArrayLiteral | NonInferrableType,
65406547
/** @internal */
65416548
InstantiatedMapped = Mapped | Instantiated,
6542-
// Object flags that uniquely identify the kind of ObjectType
6543-
/** @internal */
6544-
ObjectTypeKindMask = ClassOrInterface | Reference | Tuple | Anonymous | Mapped | ReverseMapped | EvolvingArray,
6545-
6549+
65466550
// Flags that require TypeFlags.Object
65476551
ContainsSpread = 1 << 21, // Object literal contains spread operation
65486552
ObjectRestType = 1 << 22, // Originates in object rest declaration
65496553
InstantiationExpressionType = 1 << 23, // Originates in instantiation expression
6554+
6555+
// Object flags that uniquely identify the kind of ObjectType
6556+
/** @internal */
6557+
ObjectTypeKindMask = ClassOrInterface | Reference | Tuple | Anonymous | Mapped | ReverseMapped | EvolvingArray | InstantiationExpressionType | SingleSignatureType,
6558+
65506559
/** @internal */
65516560
IsClassInstanceClone = 1 << 24, // Type is a clone of a class instance type
65526561
// Flags that require TypeFlags.Object and ObjectFlags.Reference
@@ -7532,6 +7541,7 @@ export interface CompilerOptions {
75327541
strictNullChecks?: boolean; // Always combine with strict property
75337542
strictPropertyInitialization?: boolean; // Always combine with strict property
75347543
strictBuiltinIteratorReturn?: boolean; // Always combine with strict property
7544+
stableTypeOrdering?: boolean;
75357545
stripInternal?: boolean;
75367546
/** @deprecated */
75377547
suppressExcessPropertyErrors?: boolean;

tests/baselines/reference/api/typescript.d.ts

Lines changed: 48 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -6593,53 +6593,53 @@ declare namespace ts {
65936593
enum TypeFlags {
65946594
Any = 1,
65956595
Unknown = 2,
6596-
String = 4,
6597-
Number = 8,
6598-
Boolean = 16,
6599-
Enum = 32,
6600-
BigInt = 64,
6601-
StringLiteral = 128,
6602-
NumberLiteral = 256,
6603-
BooleanLiteral = 512,
6604-
EnumLiteral = 1024,
6605-
BigIntLiteral = 2048,
6606-
ESSymbol = 4096,
6607-
UniqueESSymbol = 8192,
6608-
Void = 16384,
6609-
Undefined = 32768,
6610-
Null = 65536,
6611-
Never = 131072,
6612-
TypeParameter = 262144,
6613-
Object = 524288,
6614-
Union = 1048576,
6615-
Intersection = 2097152,
6616-
Index = 4194304,
6617-
IndexedAccess = 8388608,
6618-
Conditional = 16777216,
6619-
Substitution = 33554432,
6620-
NonPrimitive = 67108864,
6621-
TemplateLiteral = 134217728,
6622-
StringMapping = 268435456,
6623-
Literal = 2944,
6624-
Unit = 109472,
6625-
Freshable = 2976,
6626-
StringOrNumberLiteral = 384,
6627-
PossiblyFalsy = 117724,
6628-
StringLike = 402653316,
6629-
NumberLike = 296,
6630-
BigIntLike = 2112,
6631-
BooleanLike = 528,
6632-
EnumLike = 1056,
6633-
ESSymbolLike = 12288,
6634-
VoidLike = 49152,
6635-
UnionOrIntersection = 3145728,
6636-
StructuredType = 3670016,
6637-
TypeVariable = 8650752,
6638-
InstantiableNonPrimitive = 58982400,
6639-
InstantiablePrimitive = 406847488,
6640-
Instantiable = 465829888,
6641-
StructuredOrInstantiable = 469499904,
6642-
Narrowable = 536624127,
6596+
Undefined = 4,
6597+
Null = 8,
6598+
Void = 16,
6599+
String = 32,
6600+
Number = 64,
6601+
BigInt = 128,
6602+
Boolean = 256,
6603+
ESSymbol = 512,
6604+
StringLiteral = 1024,
6605+
NumberLiteral = 2048,
6606+
BigIntLiteral = 4096,
6607+
BooleanLiteral = 8192,
6608+
UniqueESSymbol = 16384,
6609+
EnumLiteral = 32768,
6610+
Enum = 65536,
6611+
NonPrimitive = 131072,
6612+
Never = 262144,
6613+
TypeParameter = 524288,
6614+
Object = 1048576,
6615+
Index = 2097152,
6616+
TemplateLiteral = 4194304,
6617+
StringMapping = 8388608,
6618+
Substitution = 16777216,
6619+
IndexedAccess = 33554432,
6620+
Conditional = 67108864,
6621+
Union = 134217728,
6622+
Intersection = 268435456,
6623+
Literal = 15360,
6624+
Unit = 97292,
6625+
Freshable = 80896,
6626+
StringOrNumberLiteral = 3072,
6627+
PossiblyFalsy = 15868,
6628+
StringLike = 12583968,
6629+
NumberLike = 67648,
6630+
BigIntLike = 4224,
6631+
BooleanLike = 8448,
6632+
EnumLike = 98304,
6633+
ESSymbolLike = 16896,
6634+
VoidLike = 20,
6635+
UnionOrIntersection = 402653184,
6636+
StructuredType = 403701760,
6637+
TypeVariable = 34078720,
6638+
InstantiableNonPrimitive = 117964800,
6639+
InstantiablePrimitive = 14680064,
6640+
Instantiable = 132644864,
6641+
StructuredOrInstantiable = 536346624,
6642+
Narrowable = 536575971,
66436643
}
66446644
type DestructuringPattern = BindingPattern | ObjectLiteralExpression | ArrayLiteralExpression;
66456645
interface Type {
@@ -7114,6 +7114,7 @@ declare namespace ts {
71147114
strictNullChecks?: boolean;
71157115
strictPropertyInitialization?: boolean;
71167116
strictBuiltinIteratorReturn?: boolean;
7117+
stableTypeOrdering?: boolean;
71177118
stripInternal?: boolean;
71187119
/** @deprecated */
71197120
suppressExcessPropertyErrors?: boolean;
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"compilerOptions": {
3+
"stableTypeOrdering": true
4+
}
5+
}

tests/baselines/reference/tsc/commandLine/help-all.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,11 @@ Raise an error when a function parameter isn't read.
271271
type: boolean
272272
default: false
273273

274+
--stableTypeOrdering
275+
Ensure types are ordered stably and deterministically across compilations.
276+
type: boolean
277+
default: true
278+
274279
--strict
275280
Enable all strict type-checking options.
276281
type: boolean

0 commit comments

Comments
 (0)