Skip to content

Commit 0208948

Browse files
authored
Add --stableTypeOrdering for TS7 ordering compat (#63084)
1 parent a84710d commit 0208948

55 files changed

Lines changed: 1249 additions & 347 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

src/compiler/checker.ts

Lines changed: 459 additions & 22 deletions
Large diffs are not rendered by default.

src/compiler/commandLineParser.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -973,6 +973,16 @@ const commandOptionsWithoutBuild: CommandLineOption[] = [
973973
description: Diagnostics.Built_in_iterators_are_instantiated_with_a_TReturn_type_of_undefined_instead_of_any,
974974
defaultValueDescription: Diagnostics.true_unless_strict_is_false,
975975
},
976+
{
977+
name: "stableTypeOrdering",
978+
type: "boolean",
979+
affectsSemanticDiagnostics: true,
980+
affectsBuildInfo: true,
981+
showInHelp: false,
982+
category: Diagnostics.Type_Checking,
983+
description: Diagnostics.Ensure_types_are_ordered_stably_and_deterministically_across_compilations,
984+
defaultValueDescription: false,
985+
},
976986
{
977987
name: "noImplicitThis",
978988
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/executeCommandLine.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -174,10 +174,11 @@ function shouldBePretty(sys: System, options: CompilerOptions | BuildOptions) {
174174
}
175175

176176
function getOptionsForHelp(commandLine: ParsedCommandLine) {
177+
const helpOptions = filter(optionDeclarations.concat(tscBuildOption), option => option.showInHelp !== false);
177178
// Sort our options by their names, (e.g. "--noImplicitAny" comes before "--watch")
178179
return !!commandLine.options.all ?
179-
toSorted(optionDeclarations.concat(tscBuildOption), (a, b) => compareStringsCaseInsensitive(a.name, b.name)) :
180-
filter(optionDeclarations.concat(tscBuildOption), v => !!v.showInSimplifiedHelpView);
180+
toSorted(helpOptions, (a, b) => compareStringsCaseInsensitive(a.name, b.name)) :
181+
filter(helpOptions, v => !!v.showInSimplifiedHelpView);
181182
}
182183

183184
function printVersion(sys: System) {
@@ -512,16 +513,16 @@ function printEasyHelp(sys: System, simpleOptions: readonly CommandLineOption[])
512513
function printAllHelp(sys: System, compilerOptions: readonly CommandLineOption[], buildOptions: readonly CommandLineOption[], watchOptions: readonly CommandLineOption[]) {
513514
let output: string[] = [...getHeader(sys, `${getDiagnosticText(Diagnostics.tsc_Colon_The_TypeScript_Compiler)} - ${getDiagnosticText(Diagnostics.Version_0, version)}`)];
514515
output = [...output, ...generateSectionOptionsOutput(sys, getDiagnosticText(Diagnostics.ALL_COMPILER_OPTIONS), compilerOptions, /*subCategory*/ true, /*beforeOptionsDescription*/ undefined, formatMessage(Diagnostics.You_can_learn_about_all_of_the_compiler_options_at_0, "https://aka.ms/tsc"))];
515-
output = [...output, ...generateSectionOptionsOutput(sys, getDiagnosticText(Diagnostics.WATCH_OPTIONS), watchOptions, /*subCategory*/ false, getDiagnosticText(Diagnostics.Including_watch_w_will_start_watching_the_current_project_for_the_file_changes_Once_set_you_can_config_watch_mode_with_Colon))];
516-
output = [...output, ...generateSectionOptionsOutput(sys, getDiagnosticText(Diagnostics.BUILD_OPTIONS), filter(buildOptions, option => option !== tscBuildOption), /*subCategory*/ false, formatMessage(Diagnostics.Using_build_b_will_make_tsc_behave_more_like_a_build_orchestrator_than_a_compiler_This_is_used_to_trigger_building_composite_projects_which_you_can_learn_more_about_at_0, "https://aka.ms/tsc-composite-builds"))];
516+
output = [...output, ...generateSectionOptionsOutput(sys, getDiagnosticText(Diagnostics.WATCH_OPTIONS), filter(watchOptions, option => option.showInHelp !== false), /*subCategory*/ false, getDiagnosticText(Diagnostics.Including_watch_w_will_start_watching_the_current_project_for_the_file_changes_Once_set_you_can_config_watch_mode_with_Colon))];
517+
output = [...output, ...generateSectionOptionsOutput(sys, getDiagnosticText(Diagnostics.BUILD_OPTIONS), filter(buildOptions, option => option !== tscBuildOption && option.showInHelp !== false), /*subCategory*/ false, formatMessage(Diagnostics.Using_build_b_will_make_tsc_behave_more_like_a_build_orchestrator_than_a_compiler_This_is_used_to_trigger_building_composite_projects_which_you_can_learn_more_about_at_0, "https://aka.ms/tsc-composite-builds"))];
517518
for (const line of output) {
518519
sys.write(line);
519520
}
520521
}
521522

522523
function printBuildHelp(sys: System, buildOptions: readonly CommandLineOption[]) {
523524
let output: string[] = [...getHeader(sys, `${getDiagnosticText(Diagnostics.tsc_Colon_The_TypeScript_Compiler)} - ${getDiagnosticText(Diagnostics.Version_0, version)}`)];
524-
output = [...output, ...generateSectionOptionsOutput(sys, getDiagnosticText(Diagnostics.BUILD_OPTIONS), filter(buildOptions, option => option !== tscBuildOption), /*subCategory*/ false, formatMessage(Diagnostics.Using_build_b_will_make_tsc_behave_more_like_a_build_orchestrator_than_a_compiler_This_is_used_to_trigger_building_composite_projects_which_you_can_learn_more_about_at_0, "https://aka.ms/tsc-composite-builds"))];
525+
output = [...output, ...generateSectionOptionsOutput(sys, getDiagnosticText(Diagnostics.BUILD_OPTIONS), filter(buildOptions, option => option !== tscBuildOption && option.showInHelp !== false), /*subCategory*/ false, formatMessage(Diagnostics.Using_build_b_will_make_tsc_behave_more_like_a_build_orchestrator_than_a_compiler_This_is_used_to_trigger_building_composite_projects_which_you_can_learn_more_about_at_0, "https://aka.ms/tsc-composite-builds"))];
525526
for (const line of output) {
526527
sys.write(line);
527528
}

src/compiler/types.ts

Lines changed: 44 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
@@ -7533,6 +7542,8 @@ export interface CompilerOptions {
75337542
strictNullChecks?: boolean; // Always combine with strict property
75347543
strictPropertyInitialization?: boolean; // Always combine with strict property
75357544
strictBuiltinIteratorReturn?: boolean; // Always combine with strict property
7545+
/** @internal */
7546+
stableTypeOrdering?: boolean;
75367547
stripInternal?: boolean;
75377548
/** @deprecated */
75387549
suppressExcessPropertyErrors?: boolean;
@@ -7751,6 +7762,7 @@ export interface CommandLineOptionBase {
77517762
isTSConfigOnly?: boolean; // True if option can only be specified via tsconfig.json file
77527763
isCommandLineOnly?: boolean;
77537764
showInSimplifiedHelpView?: boolean;
7765+
showInHelp?: boolean;
77547766
category?: DiagnosticMessage;
77557767
strictFlag?: true; // true if the option is one of the flag under strict
77567768
allowJsFlag?: true;

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

Lines changed: 47 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -6594,53 +6594,53 @@ declare namespace ts {
65946594
enum TypeFlags {
65956595
Any = 1,
65966596
Unknown = 2,
6597-
String = 4,
6598-
Number = 8,
6599-
Boolean = 16,
6600-
Enum = 32,
6601-
BigInt = 64,
6602-
StringLiteral = 128,
6603-
NumberLiteral = 256,
6604-
BooleanLiteral = 512,
6605-
EnumLiteral = 1024,
6606-
BigIntLiteral = 2048,
6607-
ESSymbol = 4096,
6608-
UniqueESSymbol = 8192,
6609-
Void = 16384,
6610-
Undefined = 32768,
6611-
Null = 65536,
6612-
Never = 131072,
6613-
TypeParameter = 262144,
6614-
Object = 524288,
6615-
Union = 1048576,
6616-
Intersection = 2097152,
6617-
Index = 4194304,
6618-
IndexedAccess = 8388608,
6619-
Conditional = 16777216,
6620-
Substitution = 33554432,
6621-
NonPrimitive = 67108864,
6622-
TemplateLiteral = 134217728,
6623-
StringMapping = 268435456,
6624-
Literal = 2944,
6625-
Unit = 109472,
6626-
Freshable = 2976,
6627-
StringOrNumberLiteral = 384,
6628-
PossiblyFalsy = 117724,
6629-
StringLike = 402653316,
6630-
NumberLike = 296,
6631-
BigIntLike = 2112,
6632-
BooleanLike = 528,
6633-
EnumLike = 1056,
6634-
ESSymbolLike = 12288,
6635-
VoidLike = 49152,
6636-
UnionOrIntersection = 3145728,
6637-
StructuredType = 3670016,
6638-
TypeVariable = 8650752,
6639-
InstantiableNonPrimitive = 58982400,
6640-
InstantiablePrimitive = 406847488,
6641-
Instantiable = 465829888,
6642-
StructuredOrInstantiable = 469499904,
6643-
Narrowable = 536624127,
6597+
Undefined = 4,
6598+
Null = 8,
6599+
Void = 16,
6600+
String = 32,
6601+
Number = 64,
6602+
BigInt = 128,
6603+
Boolean = 256,
6604+
ESSymbol = 512,
6605+
StringLiteral = 1024,
6606+
NumberLiteral = 2048,
6607+
BigIntLiteral = 4096,
6608+
BooleanLiteral = 8192,
6609+
UniqueESSymbol = 16384,
6610+
EnumLiteral = 32768,
6611+
Enum = 65536,
6612+
NonPrimitive = 131072,
6613+
Never = 262144,
6614+
TypeParameter = 524288,
6615+
Object = 1048576,
6616+
Index = 2097152,
6617+
TemplateLiteral = 4194304,
6618+
StringMapping = 8388608,
6619+
Substitution = 16777216,
6620+
IndexedAccess = 33554432,
6621+
Conditional = 67108864,
6622+
Union = 134217728,
6623+
Intersection = 268435456,
6624+
Literal = 15360,
6625+
Unit = 97292,
6626+
Freshable = 80896,
6627+
StringOrNumberLiteral = 3072,
6628+
PossiblyFalsy = 15868,
6629+
StringLike = 12583968,
6630+
NumberLike = 67648,
6631+
BigIntLike = 4224,
6632+
BooleanLike = 8448,
6633+
EnumLike = 98304,
6634+
ESSymbolLike = 16896,
6635+
VoidLike = 20,
6636+
UnionOrIntersection = 402653184,
6637+
StructuredType = 403701760,
6638+
TypeVariable = 34078720,
6639+
InstantiableNonPrimitive = 117964800,
6640+
InstantiablePrimitive = 14680064,
6641+
Instantiable = 132644864,
6642+
StructuredOrInstantiable = 536346624,
6643+
Narrowable = 536575971,
66446644
}
66456645
type DestructuringPattern = BindingPattern | ObjectLiteralExpression | ArrayLiteralExpression;
66466646
interface Type {
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+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
//// [tests/cases/compiler/stableTypeOrdering.ts] ////
2+
3+
=== stableTypeOrdering.ts ===
4+
class Message { value: string = ""; }
5+
>Message : Symbol(Message, Decl(stableTypeOrdering.ts, 0, 0))
6+
>value : Symbol(Message.value, Decl(stableTypeOrdering.ts, 0, 15))
7+
8+
function takeMessageOrArray(message: Message | Message[]) { return message; }
9+
>takeMessageOrArray : Symbol(takeMessageOrArray, Decl(stableTypeOrdering.ts, 0, 37))
10+
>message : Symbol(message, Decl(stableTypeOrdering.ts, 2, 28))
11+
>Message : Symbol(Message, Decl(stableTypeOrdering.ts, 0, 0))
12+
>Message : Symbol(Message, Decl(stableTypeOrdering.ts, 0, 0))
13+
>message : Symbol(message, Decl(stableTypeOrdering.ts, 2, 28))
14+
15+
const result1 = takeMessageOrArray(null!);
16+
>result1 : Symbol(result1, Decl(stableTypeOrdering.ts, 3, 5))
17+
>takeMessageOrArray : Symbol(takeMessageOrArray, Decl(stableTypeOrdering.ts, 0, 37))
18+
19+
function checkType(x: string | number | boolean) {
20+
>checkType : Symbol(checkType, Decl(stableTypeOrdering.ts, 3, 42))
21+
>x : Symbol(x, Decl(stableTypeOrdering.ts, 5, 19))
22+
23+
const t = typeof x;
24+
>t : Symbol(t, Decl(stableTypeOrdering.ts, 6, 9))
25+
>x : Symbol(x, Decl(stableTypeOrdering.ts, 5, 19))
26+
27+
return t;
28+
>t : Symbol(t, Decl(stableTypeOrdering.ts, 6, 9))
29+
}
30+
31+
function mixedUnion(x: string | number[] | { a: number }) {
32+
>mixedUnion : Symbol(mixedUnion, Decl(stableTypeOrdering.ts, 8, 1))
33+
>x : Symbol(x, Decl(stableTypeOrdering.ts, 10, 20))
34+
>a : Symbol(a, Decl(stableTypeOrdering.ts, 10, 44))
35+
36+
return x;
37+
>x : Symbol(x, Decl(stableTypeOrdering.ts, 10, 20))
38+
}
39+
40+
enum Color { Red, Green, Blue }
41+
>Color : Symbol(Color, Decl(stableTypeOrdering.ts, 12, 1))
42+
>Red : Symbol(Color.Red, Decl(stableTypeOrdering.ts, 14, 12))
43+
>Green : Symbol(Color.Green, Decl(stableTypeOrdering.ts, 14, 17))
44+
>Blue : Symbol(Color.Blue, Decl(stableTypeOrdering.ts, 14, 24))
45+
46+
function enumUnion(x: Color | string | string[]) {
47+
>enumUnion : Symbol(enumUnion, Decl(stableTypeOrdering.ts, 14, 31))
48+
>x : Symbol(x, Decl(stableTypeOrdering.ts, 15, 19))
49+
>Color : Symbol(Color, Decl(stableTypeOrdering.ts, 12, 1))
50+
51+
return x;
52+
>x : Symbol(x, Decl(stableTypeOrdering.ts, 15, 19))
53+
}
54+
55+
type Named = { name: string };
56+
>Named : Symbol(Named, Decl(stableTypeOrdering.ts, 17, 1))
57+
>name : Symbol(name, Decl(stableTypeOrdering.ts, 19, 14))
58+
59+
type Aged = { age: number };
60+
>Aged : Symbol(Aged, Decl(stableTypeOrdering.ts, 19, 30))
61+
>age : Symbol(age, Decl(stableTypeOrdering.ts, 20, 13))
62+
63+
type Person = Named & Aged;
64+
>Person : Symbol(Person, Decl(stableTypeOrdering.ts, 20, 28))
65+
>Named : Symbol(Named, Decl(stableTypeOrdering.ts, 17, 1))
66+
>Aged : Symbol(Aged, Decl(stableTypeOrdering.ts, 19, 30))
67+
68+
declare const person: Person | null;
69+
>person : Symbol(person, Decl(stableTypeOrdering.ts, 22, 13))
70+
>Person : Symbol(Person, Decl(stableTypeOrdering.ts, 20, 28))
71+
72+
const p = person;
73+
>p : Symbol(p, Decl(stableTypeOrdering.ts, 23, 5))
74+
>person : Symbol(person, Decl(stableTypeOrdering.ts, 22, 13))
75+

0 commit comments

Comments
 (0)