Skip to content

Commit d212cdc

Browse files
ahejlsbergZzzen
authored andcommitted
Leading and middle rest elements in tuple types (microsoft#41544)
* Support starting and middle rest elements in tuples * Accept new baselines * Include all rest arguments in error span * Accept new baselines * Fix tests * Add new tests * Fix lint errors
1 parent 88e91e2 commit d212cdc

24 files changed

+2339
-629
lines changed

src/compiler/checker.ts

Lines changed: 139 additions & 111 deletions
Large diffs are not rendered by default.

src/compiler/diagnosticMessages.json

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -843,10 +843,6 @@
843843
"category": "Error",
844844
"code": 1255
845845
},
846-
"A rest element must be last in a tuple type.": {
847-
"category": "Error",
848-
"code": 1256
849-
},
850846
"A required element cannot follow an optional element.": {
851847
"category": "Error",
852848
"code": 1257
@@ -875,6 +871,14 @@
875871
"category": "Error",
876872
"code": 1264
877873
},
874+
"A rest element cannot follow another rest element.": {
875+
"category": "Error",
876+
"code": 1265
877+
},
878+
"An optional element cannot follow a rest element.": {
879+
"category": "Error",
880+
"code": 1266
881+
},
878882

879883
"'with' statements are not allowed in an async function block.": {
880884
"category": "Error",
@@ -2621,9 +2625,25 @@
26212625
"category": "Error",
26222626
"code": 2621
26232627
},
2624-
"Element at index {0} is variadic in one type but not in the other.": {
2628+
"Source provides no match for required element at position {0} in target.": {
2629+
"category": "Error",
2630+
"code": 2623
2631+
},
2632+
"Source provides no match for variadic element at position {0} in target.": {
2633+
"category": "Error",
2634+
"code": 2624
2635+
},
2636+
"Variadic element at position {0} in source does not match element at position {1} in target.": {
2637+
"category": "Error",
2638+
"code": 2625
2639+
},
2640+
"Type at position {0} in source is not compatible with type at position {1} in target.": {
2641+
"category": "Error",
2642+
"code": 2626
2643+
},
2644+
"Type at positions {0} through {1} in source is not compatible with type at position {2} in target.": {
26252645
"category": "Error",
2626-
"code": 2622
2646+
"code": 2627
26272647
},
26282648

26292649
"Cannot augment module '{0}' with value exports because it resolves to a non-module entity.": {

src/compiler/types.ts

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5251,18 +5251,21 @@ namespace ts {
52515251
}
52525252

52535253
export const enum ElementFlags {
5254-
Required = 1 << 0, // T
5255-
Optional = 1 << 1, // T?
5256-
Rest = 1 << 2, // ...T[]
5257-
Variadic = 1 << 3, // ...T
5258-
Variable = Rest | Variadic,
5254+
Required = 1 << 0, // T
5255+
Optional = 1 << 1, // T?
5256+
Rest = 1 << 2, // ...T[]
5257+
Variadic = 1 << 3, // ...T
5258+
Fixed = Required | Optional,
5259+
Variable = Rest | Variadic,
5260+
NonRequired = Optional | Rest | Variadic,
5261+
NonRest = Required | Optional | Variadic,
52595262
}
52605263

52615264
export interface TupleType extends GenericType {
52625265
elementFlags: readonly ElementFlags[];
5263-
minLength: number;
5264-
fixedLength: number;
5265-
hasRestElement: boolean;
5266+
minLength: number; // Number of required or variadic elements
5267+
fixedLength: number; // Number of initial required or optional elements
5268+
hasRestElement: boolean; // True if tuple has any rest or variadic elements
52665269
combinedFlags: ElementFlags;
52675270
readonly: boolean;
52685271
labeledElementDeclarations?: readonly (NamedTupleMember | ParameterDeclaration)[];

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2591,7 +2591,10 @@ declare namespace ts {
25912591
Optional = 2,
25922592
Rest = 4,
25932593
Variadic = 8,
2594-
Variable = 12
2594+
Fixed = 3,
2595+
Variable = 12,
2596+
NonRequired = 14,
2597+
NonRest = 11
25952598
}
25962599
export interface TupleType extends GenericType {
25972600
elementFlags: readonly ElementFlags[];

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2591,7 +2591,10 @@ declare namespace ts {
25912591
Optional = 2,
25922592
Rest = 4,
25932593
Variadic = 8,
2594-
Variable = 12
2594+
Fixed = 3,
2595+
Variable = 12,
2596+
NonRequired = 14,
2597+
NonRest = 11
25952598
}
25962599
export interface TupleType extends GenericType {
25972600
elementFlags: readonly ElementFlags[];

tests/baselines/reference/for-of39.errors.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ tests/cases/conformance/es6/for-ofStatements/for-of39.ts(1,11): error TS2769: No
77
Type 'IteratorYieldResult<[string, number] | [string, true]>' is not assignable to type 'IteratorYieldResult<readonly [string, boolean]>'.
88
Type '[string, number] | [string, true]' is not assignable to type 'readonly [string, boolean]'.
99
Type '[string, number]' is not assignable to type 'readonly [string, boolean]'.
10-
Types of property '1' are incompatible.
10+
Type at position 1 in source is not compatible with type at position 1 in target.
1111
Type 'number' is not assignable to type 'boolean'.
1212
Overload 2 of 3, '(entries?: readonly (readonly [string, boolean])[]): Map<string, boolean>', gave the following error.
1313
Type 'number' is not assignable to type 'boolean'.
@@ -25,7 +25,7 @@ tests/cases/conformance/es6/for-ofStatements/for-of39.ts(1,11): error TS2769: No
2525
!!! error TS2769: Type 'IteratorYieldResult<[string, number] | [string, true]>' is not assignable to type 'IteratorYieldResult<readonly [string, boolean]>'.
2626
!!! error TS2769: Type '[string, number] | [string, true]' is not assignable to type 'readonly [string, boolean]'.
2727
!!! error TS2769: Type '[string, number]' is not assignable to type 'readonly [string, boolean]'.
28-
!!! error TS2769: Types of property '1' are incompatible.
28+
!!! error TS2769: Type at position 1 in source is not compatible with type at position 1 in target.
2929
!!! error TS2769: Type 'number' is not assignable to type 'boolean'.
3030
!!! error TS2769: Overload 2 of 3, '(entries?: readonly (readonly [string, boolean])[]): Map<string, boolean>', gave the following error.
3131
!!! error TS2769: Type 'number' is not assignable to type 'boolean'.

tests/baselines/reference/genericRestParameters2.types

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -408,7 +408,7 @@ f20(42, "hello", ...t3);
408408
>t3 : boolean[]
409409

410410
f20(42, "hello", ...t2, true);
411-
>f20(42, "hello", ...t2, true) : [number, string, string, ...boolean[]]
411+
>f20(42, "hello", ...t2, true) : [number, string, string, ...boolean[], boolean]
412412
>f20 : <T extends unknown[]>(...args: T) => T
413413
>42 : 42
414414
>"hello" : "hello"

tests/baselines/reference/genericRestParameters3.errors.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ tests/cases/conformance/types/rest/genericRestParameters3.ts(59,5): error TS2345
114114

115115
let a = bar(10, 20);
116116
let b = bar<CoolArray<number>>(10, 20); // Error
117-
~~
117+
~~~~~~
118118
!!! error TS2345: Argument of type '[10, 20]' is not assignable to parameter of type 'CoolArray<number>'.
119119
!!! error TS2345: Property 'hello' is missing in type '[10, 20]' but required in type 'CoolArray<number>'.
120120
!!! related TS2728 tests/cases/conformance/types/rest/genericRestParameters3.ts:30:5: 'hello' is declared here.
@@ -133,7 +133,7 @@ tests/cases/conformance/types/rest/genericRestParameters3.ts(59,5): error TS2345
133133
!!! error TS2345: Property 'hello' is missing in type '[number]' but required in type 'CoolArray<unknown>'.
134134
!!! related TS2728 tests/cases/conformance/types/rest/genericRestParameters3.ts:30:5: 'hello' is declared here.
135135
baz(1, 2); // Error
136-
~
136+
~~~~
137137
!!! error TS2345: Argument of type '[number, number]' is not assignable to parameter of type 'CoolArray<unknown>'.
138138
!!! error TS2345: Property 'hello' is missing in type '[number, number]' but required in type 'CoolArray<unknown>'.
139139
!!! related TS2728 tests/cases/conformance/types/rest/genericRestParameters3.ts:30:5: 'hello' is declared here.

tests/baselines/reference/iterableArrayPattern28.errors.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ tests/cases/conformance/es6/destructuring/iterableArrayPattern28.ts(2,24): error
77
Type 'IteratorYieldResult<[string, number] | [string, boolean]>' is not assignable to type 'IteratorYieldResult<readonly [string, number]>'.
88
Type '[string, number] | [string, boolean]' is not assignable to type 'readonly [string, number]'.
99
Type '[string, boolean]' is not assignable to type 'readonly [string, number]'.
10-
Types of property '1' are incompatible.
10+
Type at position 1 in source is not compatible with type at position 1 in target.
1111
Type 'boolean' is not assignable to type 'number'.
1212
Overload 2 of 3, '(entries?: readonly (readonly [string, number])[]): Map<string, number>', gave the following error.
1313
Type 'boolean' is not assignable to type 'number'.
@@ -26,7 +26,7 @@ tests/cases/conformance/es6/destructuring/iterableArrayPattern28.ts(2,24): error
2626
!!! error TS2769: Type 'IteratorYieldResult<[string, number] | [string, boolean]>' is not assignable to type 'IteratorYieldResult<readonly [string, number]>'.
2727
!!! error TS2769: Type '[string, number] | [string, boolean]' is not assignable to type 'readonly [string, number]'.
2828
!!! error TS2769: Type '[string, boolean]' is not assignable to type 'readonly [string, number]'.
29-
!!! error TS2769: Types of property '1' are incompatible.
29+
!!! error TS2769: Type at position 1 in source is not compatible with type at position 1 in target.
3030
!!! error TS2769: Type 'boolean' is not assignable to type 'number'.
3131
!!! error TS2769: Overload 2 of 3, '(entries?: readonly (readonly [string, number])[]): Map<string, number>', gave the following error.
3232
!!! error TS2769: Type 'boolean' is not assignable to type 'number'.

tests/baselines/reference/optionalTupleElements1.errors.txt

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
tests/cases/conformance/types/tuple/optionalTupleElements1.ts(11,29): error TS1257: A required element cannot follow an optional element.
22
tests/cases/conformance/types/tuple/optionalTupleElements1.ts(15,5): error TS2322: Type 'T2' is not assignable to type 'T1'.
3-
Property '2' is optional in type '[number, string, (boolean | undefined)?]' but required in type '[number, string, boolean]'.
3+
Source provides no match for required element at position 2 in target.
44
tests/cases/conformance/types/tuple/optionalTupleElements1.ts(16,5): error TS2322: Type 'T3' is not assignable to type 'T1'.
5-
Property '1' is optional in type '[number, (string | undefined)?, (boolean | undefined)?]' but required in type '[number, string, boolean]'.
5+
Source provides no match for required element at position 1 in target.
66
tests/cases/conformance/types/tuple/optionalTupleElements1.ts(17,5): error TS2322: Type 'T4' is not assignable to type 'T1'.
7-
Property '0' is optional in type '[(number | undefined)?, (string | undefined)?, (boolean | undefined)?]' but required in type '[number, string, boolean]'.
7+
Source provides no match for required element at position 0 in target.
88
tests/cases/conformance/types/tuple/optionalTupleElements1.ts(20,5): error TS2322: Type 'T3' is not assignable to type 'T2'.
9-
Property '1' is optional in type '[number, (string | undefined)?, (boolean | undefined)?]' but required in type '[number, string, (boolean | undefined)?]'.
9+
Source provides no match for required element at position 1 in target.
1010
tests/cases/conformance/types/tuple/optionalTupleElements1.ts(21,5): error TS2322: Type 'T4' is not assignable to type 'T2'.
11-
Property '0' is optional in type '[(number | undefined)?, (string | undefined)?, (boolean | undefined)?]' but required in type '[number, string, (boolean | undefined)?]'.
11+
Source provides no match for required element at position 0 in target.
1212
tests/cases/conformance/types/tuple/optionalTupleElements1.ts(25,5): error TS2322: Type 'T4' is not assignable to type 'T3'.
13-
Property '0' is optional in type '[(number | undefined)?, (string | undefined)?, (boolean | undefined)?]' but required in type '[number, (string | undefined)?, (boolean | undefined)?]'.
13+
Source provides no match for required element at position 0 in target.
1414

1515

1616
==== tests/cases/conformance/types/tuple/optionalTupleElements1.ts (7 errors) ====
@@ -33,32 +33,32 @@ tests/cases/conformance/types/tuple/optionalTupleElements1.ts(25,5): error TS232
3333
t1 = t2; // Error
3434
~~
3535
!!! error TS2322: Type 'T2' is not assignable to type 'T1'.
36-
!!! error TS2322: Property '2' is optional in type '[number, string, (boolean | undefined)?]' but required in type '[number, string, boolean]'.
36+
!!! error TS2322: Source provides no match for required element at position 2 in target.
3737
t1 = t3; // Error
3838
~~
3939
!!! error TS2322: Type 'T3' is not assignable to type 'T1'.
40-
!!! error TS2322: Property '1' is optional in type '[number, (string | undefined)?, (boolean | undefined)?]' but required in type '[number, string, boolean]'.
40+
!!! error TS2322: Source provides no match for required element at position 1 in target.
4141
t1 = t4; // Error
4242
~~
4343
!!! error TS2322: Type 'T4' is not assignable to type 'T1'.
44-
!!! error TS2322: Property '0' is optional in type '[(number | undefined)?, (string | undefined)?, (boolean | undefined)?]' but required in type '[number, string, boolean]'.
44+
!!! error TS2322: Source provides no match for required element at position 0 in target.
4545
t2 = t1;
4646
t2 = t2;
4747
t2 = t3; // Error
4848
~~
4949
!!! error TS2322: Type 'T3' is not assignable to type 'T2'.
50-
!!! error TS2322: Property '1' is optional in type '[number, (string | undefined)?, (boolean | undefined)?]' but required in type '[number, string, (boolean | undefined)?]'.
50+
!!! error TS2322: Source provides no match for required element at position 1 in target.
5151
t2 = t4; // Error
5252
~~
5353
!!! error TS2322: Type 'T4' is not assignable to type 'T2'.
54-
!!! error TS2322: Property '0' is optional in type '[(number | undefined)?, (string | undefined)?, (boolean | undefined)?]' but required in type '[number, string, (boolean | undefined)?]'.
54+
!!! error TS2322: Source provides no match for required element at position 0 in target.
5555
t3 = t1;
5656
t3 = t2;
5757
t3 = t3;
5858
t3 = t4; // Error
5959
~~
6060
!!! error TS2322: Type 'T4' is not assignable to type 'T3'.
61-
!!! error TS2322: Property '0' is optional in type '[(number | undefined)?, (string | undefined)?, (boolean | undefined)?]' but required in type '[number, (string | undefined)?, (boolean | undefined)?]'.
61+
!!! error TS2322: Source provides no match for required element at position 0 in target.
6262
t4 = t1;
6363
t4 = t2;
6464
t4 = t3;

0 commit comments

Comments
 (0)