Skip to content

Commit 18e1949

Browse files
authored
Fixed parenthesized array literal expressions spread in calls not being tupleized (#54623)
1 parent dd3e81a commit 18e1949

21 files changed

+424
-210
lines changed

src/compiler/checker.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29965,17 +29965,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2996529965
(node.kind === SyntaxKind.BinaryExpression && (node as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken);
2996629966
}
2996729967

29968+
function isSpreadIntoCallOrNew(node: ArrayLiteralExpression) {
29969+
const parent = walkUpParenthesizedExpressions(node.parent);
29970+
return isSpreadElement(parent) && isCallOrNewExpression(parent.parent);
29971+
}
29972+
2996829973
function checkArrayLiteral(node: ArrayLiteralExpression, checkMode: CheckMode | undefined, forceTuple: boolean | undefined): Type {
2996929974
const elements = node.elements;
2997029975
const elementCount = elements.length;
2997129976
const elementTypes: Type[] = [];
2997229977
const elementFlags: ElementFlags[] = [];
2997329978
pushCachedContextualType(node);
2997429979
const inDestructuringPattern = isAssignmentTarget(node);
29975-
const isSpreadIntoCallOrNew = isSpreadElement(node.parent) && isCallOrNewExpression(node.parent.parent);
29976-
const inConstContext = isSpreadIntoCallOrNew || isConstContext(node);
29980+
const inConstContext = isConstContext(node);
2997729981
const contextualType = getApparentTypeOfContextualType(node, /*contextFlags*/ undefined);
29978-
const inTupleContext = isSpreadIntoCallOrNew || !!contextualType && someType(contextualType, isTupleLikeType);
29982+
const inTupleContext = isSpreadIntoCallOrNew(node) || !!contextualType && someType(contextualType, isTupleLikeType);
2997929983
let hasOmittedExpression = false;
2998029984
for (let i = 0; i < elementCount; i++) {
2998129985
const e = elements[i];

tests/baselines/reference/arraySpreadInCall.errors.txt

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
arraySpreadInCall.ts(21,12): error TS2554: Expected 0-1 arguments, but got 2.
1+
arraySpreadInCall.ts(32,12): error TS2554: Expected 0-1 arguments, but got 2.
22

33

44
==== arraySpreadInCall.ts (1 errors) ====
@@ -8,14 +8,25 @@ arraySpreadInCall.ts(21,12): error TS2554: Expected 0-1 arguments, but got 2.
88
f1(1, 2, ...[3, 4], 5, 6);
99
f1(1, 2, ...[3], 4, ...[5, 6]);
1010
f1(...[1, 2], ...[3, 4], ...[5, 6]);
11+
f1(...(([1, 2])), ...(((([3, 4])))), ...([5, 6]));
1112

1213
declare function f2<T extends unknown[]>(...args: T): T;
1314
const x21 = f2(...[1, 'foo'])
1415
const x22 = f2(true, ...[1, 'foo'])
16+
const x23 = f2(...([1, 'foo']))
17+
const x24 = f2(true, ...([1, 'foo']))
1518

1619
declare function f3<T extends readonly unknown[]>(...args: T): T;
1720
const x31 = f3(...[1, 'foo'])
1821
const x32 = f3(true, ...[1, 'foo'])
22+
const x33 = f3(...([1, 'foo']))
23+
const x34 = f3(true, ...([1, 'foo']))
24+
25+
declare function f4<const T extends readonly unknown[]>(...args: T): T;
26+
const x41 = f4(...[1, 'foo'])
27+
const x42 = f4(true, ...[1, 'foo'])
28+
const x43 = f4(...([1, 'foo']))
29+
const x44 = f4(true, ...([1, 'foo']))
1930

2031
// dicovered in #52845#issuecomment-1459132562
2132
interface IAction {

tests/baselines/reference/arraySpreadInCall.symbols

Lines changed: 68 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -25,51 +25,93 @@ f1(1, 2, ...[3], 4, ...[5, 6]);
2525
f1(...[1, 2], ...[3, 4], ...[5, 6]);
2626
>f1 : Symbol(f1, Decl(arraySpreadInCall.ts, 0, 0))
2727

28+
f1(...(([1, 2])), ...(((([3, 4])))), ...([5, 6]));
29+
>f1 : Symbol(f1, Decl(arraySpreadInCall.ts, 0, 0))
30+
2831
declare function f2<T extends unknown[]>(...args: T): T;
29-
>f2 : Symbol(f2, Decl(arraySpreadInCall.ts, 5, 36))
30-
>T : Symbol(T, Decl(arraySpreadInCall.ts, 7, 20))
31-
>args : Symbol(args, Decl(arraySpreadInCall.ts, 7, 41))
32-
>T : Symbol(T, Decl(arraySpreadInCall.ts, 7, 20))
33-
>T : Symbol(T, Decl(arraySpreadInCall.ts, 7, 20))
32+
>f2 : Symbol(f2, Decl(arraySpreadInCall.ts, 6, 50))
33+
>T : Symbol(T, Decl(arraySpreadInCall.ts, 8, 20))
34+
>args : Symbol(args, Decl(arraySpreadInCall.ts, 8, 41))
35+
>T : Symbol(T, Decl(arraySpreadInCall.ts, 8, 20))
36+
>T : Symbol(T, Decl(arraySpreadInCall.ts, 8, 20))
3437

3538
const x21 = f2(...[1, 'foo'])
36-
>x21 : Symbol(x21, Decl(arraySpreadInCall.ts, 8, 5))
37-
>f2 : Symbol(f2, Decl(arraySpreadInCall.ts, 5, 36))
39+
>x21 : Symbol(x21, Decl(arraySpreadInCall.ts, 9, 5))
40+
>f2 : Symbol(f2, Decl(arraySpreadInCall.ts, 6, 50))
3841

3942
const x22 = f2(true, ...[1, 'foo'])
40-
>x22 : Symbol(x22, Decl(arraySpreadInCall.ts, 9, 5))
41-
>f2 : Symbol(f2, Decl(arraySpreadInCall.ts, 5, 36))
43+
>x22 : Symbol(x22, Decl(arraySpreadInCall.ts, 10, 5))
44+
>f2 : Symbol(f2, Decl(arraySpreadInCall.ts, 6, 50))
45+
46+
const x23 = f2(...([1, 'foo']))
47+
>x23 : Symbol(x23, Decl(arraySpreadInCall.ts, 11, 5))
48+
>f2 : Symbol(f2, Decl(arraySpreadInCall.ts, 6, 50))
49+
50+
const x24 = f2(true, ...([1, 'foo']))
51+
>x24 : Symbol(x24, Decl(arraySpreadInCall.ts, 12, 5))
52+
>f2 : Symbol(f2, Decl(arraySpreadInCall.ts, 6, 50))
4253

4354
declare function f3<T extends readonly unknown[]>(...args: T): T;
44-
>f3 : Symbol(f3, Decl(arraySpreadInCall.ts, 9, 35))
45-
>T : Symbol(T, Decl(arraySpreadInCall.ts, 11, 20))
46-
>args : Symbol(args, Decl(arraySpreadInCall.ts, 11, 50))
47-
>T : Symbol(T, Decl(arraySpreadInCall.ts, 11, 20))
48-
>T : Symbol(T, Decl(arraySpreadInCall.ts, 11, 20))
55+
>f3 : Symbol(f3, Decl(arraySpreadInCall.ts, 12, 37))
56+
>T : Symbol(T, Decl(arraySpreadInCall.ts, 14, 20))
57+
>args : Symbol(args, Decl(arraySpreadInCall.ts, 14, 50))
58+
>T : Symbol(T, Decl(arraySpreadInCall.ts, 14, 20))
59+
>T : Symbol(T, Decl(arraySpreadInCall.ts, 14, 20))
4960

5061
const x31 = f3(...[1, 'foo'])
51-
>x31 : Symbol(x31, Decl(arraySpreadInCall.ts, 12, 5))
52-
>f3 : Symbol(f3, Decl(arraySpreadInCall.ts, 9, 35))
62+
>x31 : Symbol(x31, Decl(arraySpreadInCall.ts, 15, 5))
63+
>f3 : Symbol(f3, Decl(arraySpreadInCall.ts, 12, 37))
5364

5465
const x32 = f3(true, ...[1, 'foo'])
55-
>x32 : Symbol(x32, Decl(arraySpreadInCall.ts, 13, 5))
56-
>f3 : Symbol(f3, Decl(arraySpreadInCall.ts, 9, 35))
66+
>x32 : Symbol(x32, Decl(arraySpreadInCall.ts, 16, 5))
67+
>f3 : Symbol(f3, Decl(arraySpreadInCall.ts, 12, 37))
68+
69+
const x33 = f3(...([1, 'foo']))
70+
>x33 : Symbol(x33, Decl(arraySpreadInCall.ts, 17, 5))
71+
>f3 : Symbol(f3, Decl(arraySpreadInCall.ts, 12, 37))
72+
73+
const x34 = f3(true, ...([1, 'foo']))
74+
>x34 : Symbol(x34, Decl(arraySpreadInCall.ts, 18, 5))
75+
>f3 : Symbol(f3, Decl(arraySpreadInCall.ts, 12, 37))
76+
77+
declare function f4<const T extends readonly unknown[]>(...args: T): T;
78+
>f4 : Symbol(f4, Decl(arraySpreadInCall.ts, 18, 37))
79+
>T : Symbol(T, Decl(arraySpreadInCall.ts, 20, 20))
80+
>args : Symbol(args, Decl(arraySpreadInCall.ts, 20, 56))
81+
>T : Symbol(T, Decl(arraySpreadInCall.ts, 20, 20))
82+
>T : Symbol(T, Decl(arraySpreadInCall.ts, 20, 20))
83+
84+
const x41 = f4(...[1, 'foo'])
85+
>x41 : Symbol(x41, Decl(arraySpreadInCall.ts, 21, 5))
86+
>f4 : Symbol(f4, Decl(arraySpreadInCall.ts, 18, 37))
87+
88+
const x42 = f4(true, ...[1, 'foo'])
89+
>x42 : Symbol(x42, Decl(arraySpreadInCall.ts, 22, 5))
90+
>f4 : Symbol(f4, Decl(arraySpreadInCall.ts, 18, 37))
91+
92+
const x43 = f4(...([1, 'foo']))
93+
>x43 : Symbol(x43, Decl(arraySpreadInCall.ts, 23, 5))
94+
>f4 : Symbol(f4, Decl(arraySpreadInCall.ts, 18, 37))
95+
96+
const x44 = f4(true, ...([1, 'foo']))
97+
>x44 : Symbol(x44, Decl(arraySpreadInCall.ts, 24, 5))
98+
>f4 : Symbol(f4, Decl(arraySpreadInCall.ts, 18, 37))
5799

58100
// dicovered in #52845#issuecomment-1459132562
59101
interface IAction {
60-
>IAction : Symbol(IAction, Decl(arraySpreadInCall.ts, 13, 35))
102+
>IAction : Symbol(IAction, Decl(arraySpreadInCall.ts, 24, 37))
61103

62104
run(event?: unknown): unknown;
63-
>run : Symbol(IAction.run, Decl(arraySpreadInCall.ts, 16, 19))
64-
>event : Symbol(event, Decl(arraySpreadInCall.ts, 17, 8))
105+
>run : Symbol(IAction.run, Decl(arraySpreadInCall.ts, 27, 19))
106+
>event : Symbol(event, Decl(arraySpreadInCall.ts, 28, 8))
65107
}
66108
declare const action: IAction
67-
>action : Symbol(action, Decl(arraySpreadInCall.ts, 19, 13))
68-
>IAction : Symbol(IAction, Decl(arraySpreadInCall.ts, 13, 35))
109+
>action : Symbol(action, Decl(arraySpreadInCall.ts, 30, 13))
110+
>IAction : Symbol(IAction, Decl(arraySpreadInCall.ts, 24, 37))
69111

70112
action.run(...[100, 'foo']) // error
71-
>action.run : Symbol(IAction.run, Decl(arraySpreadInCall.ts, 16, 19))
72-
>action : Symbol(action, Decl(arraySpreadInCall.ts, 19, 13))
73-
>run : Symbol(IAction.run, Decl(arraySpreadInCall.ts, 16, 19))
113+
>action.run : Symbol(IAction.run, Decl(arraySpreadInCall.ts, 27, 19))
114+
>action : Symbol(action, Decl(arraySpreadInCall.ts, 30, 13))
115+
>run : Symbol(IAction.run, Decl(arraySpreadInCall.ts, 27, 19))
74116

75117

tests/baselines/reference/arraySpreadInCall.types

Lines changed: 122 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,15 @@ f1(1, 2, 3, 4, ...[5, 6]);
1818
>3 : 3
1919
>4 : 4
2020
>...[5, 6] : number
21-
>[5, 6] : readonly [number, number]
21+
>[5, 6] : [number, number]
2222
>5 : 5
2323
>6 : 6
2424

2525
f1(...[1], 2, 3, 4, 5, 6);
2626
>f1(...[1], 2, 3, 4, 5, 6) : void
2727
>f1 : (a: number, b: number, c: number, d: number, e: number, f: number) => void
2828
>...[1] : number
29-
>[1] : readonly [number]
29+
>[1] : [number]
3030
>1 : 1
3131
>2 : 2
3232
>3 : 3
@@ -40,7 +40,7 @@ f1(1, 2, ...[3, 4], 5, 6);
4040
>1 : 1
4141
>2 : 2
4242
>...[3, 4] : number
43-
>[3, 4] : readonly [number, number]
43+
>[3, 4] : [number, number]
4444
>3 : 3
4545
>4 : 4
4646
>5 : 5
@@ -52,27 +52,50 @@ f1(1, 2, ...[3], 4, ...[5, 6]);
5252
>1 : 1
5353
>2 : 2
5454
>...[3] : number
55-
>[3] : readonly [number]
55+
>[3] : [number]
5656
>3 : 3
5757
>4 : 4
5858
>...[5, 6] : number
59-
>[5, 6] : readonly [number, number]
59+
>[5, 6] : [number, number]
6060
>5 : 5
6161
>6 : 6
6262

6363
f1(...[1, 2], ...[3, 4], ...[5, 6]);
6464
>f1(...[1, 2], ...[3, 4], ...[5, 6]) : void
6565
>f1 : (a: number, b: number, c: number, d: number, e: number, f: number) => void
6666
>...[1, 2] : number
67-
>[1, 2] : readonly [number, number]
67+
>[1, 2] : [number, number]
6868
>1 : 1
6969
>2 : 2
7070
>...[3, 4] : number
71-
>[3, 4] : readonly [number, number]
71+
>[3, 4] : [number, number]
7272
>3 : 3
7373
>4 : 4
7474
>...[5, 6] : number
75-
>[5, 6] : readonly [number, number]
75+
>[5, 6] : [number, number]
76+
>5 : 5
77+
>6 : 6
78+
79+
f1(...(([1, 2])), ...(((([3, 4])))), ...([5, 6]));
80+
>f1(...(([1, 2])), ...(((([3, 4])))), ...([5, 6])) : void
81+
>f1 : (a: number, b: number, c: number, d: number, e: number, f: number) => void
82+
>...(([1, 2])) : number
83+
>(([1, 2])) : [number, number]
84+
>([1, 2]) : [number, number]
85+
>[1, 2] : [number, number]
86+
>1 : 1
87+
>2 : 2
88+
>...(((([3, 4])))) : number
89+
>(((([3, 4])))) : [number, number]
90+
>((([3, 4]))) : [number, number]
91+
>(([3, 4])) : [number, number]
92+
>([3, 4]) : [number, number]
93+
>[3, 4] : [number, number]
94+
>3 : 3
95+
>4 : 4
96+
>...([5, 6]) : number
97+
>([5, 6]) : [number, number]
98+
>[5, 6] : [number, number]
7699
>5 : 5
77100
>6 : 6
78101

@@ -85,7 +108,7 @@ const x21 = f2(...[1, 'foo'])
85108
>f2(...[1, 'foo']) : [number, string]
86109
>f2 : <T extends unknown[]>(...args: T) => T
87110
>...[1, 'foo'] : string | number
88-
>[1, 'foo'] : readonly [number, string]
111+
>[1, 'foo'] : [number, string]
89112
>1 : 1
90113
>'foo' : "foo"
91114

@@ -95,7 +118,28 @@ const x22 = f2(true, ...[1, 'foo'])
95118
>f2 : <T extends unknown[]>(...args: T) => T
96119
>true : true
97120
>...[1, 'foo'] : string | number
98-
>[1, 'foo'] : readonly [number, string]
121+
>[1, 'foo'] : [number, string]
122+
>1 : 1
123+
>'foo' : "foo"
124+
125+
const x23 = f2(...([1, 'foo']))
126+
>x23 : [number, string]
127+
>f2(...([1, 'foo'])) : [number, string]
128+
>f2 : <T extends unknown[]>(...args: T) => T
129+
>...([1, 'foo']) : string | number
130+
>([1, 'foo']) : [number, string]
131+
>[1, 'foo'] : [number, string]
132+
>1 : 1
133+
>'foo' : "foo"
134+
135+
const x24 = f2(true, ...([1, 'foo']))
136+
>x24 : [boolean, number, string]
137+
>f2(true, ...([1, 'foo'])) : [boolean, number, string]
138+
>f2 : <T extends unknown[]>(...args: T) => T
139+
>true : true
140+
>...([1, 'foo']) : string | number
141+
>([1, 'foo']) : [number, string]
142+
>[1, 'foo'] : [number, string]
99143
>1 : 1
100144
>'foo' : "foo"
101145

@@ -108,7 +152,7 @@ const x31 = f3(...[1, 'foo'])
108152
>f3(...[1, 'foo']) : [number, string]
109153
>f3 : <T extends readonly unknown[]>(...args: T) => T
110154
>...[1, 'foo'] : string | number
111-
>[1, 'foo'] : readonly [number, string]
155+
>[1, 'foo'] : [number, string]
112156
>1 : 1
113157
>'foo' : "foo"
114158

@@ -118,7 +162,72 @@ const x32 = f3(true, ...[1, 'foo'])
118162
>f3 : <T extends readonly unknown[]>(...args: T) => T
119163
>true : true
120164
>...[1, 'foo'] : string | number
121-
>[1, 'foo'] : readonly [number, string]
165+
>[1, 'foo'] : [number, string]
166+
>1 : 1
167+
>'foo' : "foo"
168+
169+
const x33 = f3(...([1, 'foo']))
170+
>x33 : [number, string]
171+
>f3(...([1, 'foo'])) : [number, string]
172+
>f3 : <T extends readonly unknown[]>(...args: T) => T
173+
>...([1, 'foo']) : string | number
174+
>([1, 'foo']) : [number, string]
175+
>[1, 'foo'] : [number, string]
176+
>1 : 1
177+
>'foo' : "foo"
178+
179+
const x34 = f3(true, ...([1, 'foo']))
180+
>x34 : [boolean, number, string]
181+
>f3(true, ...([1, 'foo'])) : [boolean, number, string]
182+
>f3 : <T extends readonly unknown[]>(...args: T) => T
183+
>true : true
184+
>...([1, 'foo']) : string | number
185+
>([1, 'foo']) : [number, string]
186+
>[1, 'foo'] : [number, string]
187+
>1 : 1
188+
>'foo' : "foo"
189+
190+
declare function f4<const T extends readonly unknown[]>(...args: T): T;
191+
>f4 : <const T extends readonly unknown[]>(...args: T) => T
192+
>args : T
193+
194+
const x41 = f4(...[1, 'foo'])
195+
>x41 : readonly [number, string]
196+
>f4(...[1, 'foo']) : readonly [number, string]
197+
>f4 : <const T extends readonly unknown[]>(...args: T) => T
198+
>...[1, 'foo'] : string | number
199+
>[1, 'foo'] : [number, string]
200+
>1 : 1
201+
>'foo' : "foo"
202+
203+
const x42 = f4(true, ...[1, 'foo'])
204+
>x42 : readonly [true, number, string]
205+
>f4(true, ...[1, 'foo']) : readonly [true, number, string]
206+
>f4 : <const T extends readonly unknown[]>(...args: T) => T
207+
>true : true
208+
>...[1, 'foo'] : string | number
209+
>[1, 'foo'] : [number, string]
210+
>1 : 1
211+
>'foo' : "foo"
212+
213+
const x43 = f4(...([1, 'foo']))
214+
>x43 : readonly [number, string]
215+
>f4(...([1, 'foo'])) : readonly [number, string]
216+
>f4 : <const T extends readonly unknown[]>(...args: T) => T
217+
>...([1, 'foo']) : string | number
218+
>([1, 'foo']) : [number, string]
219+
>[1, 'foo'] : [number, string]
220+
>1 : 1
221+
>'foo' : "foo"
222+
223+
const x44 = f4(true, ...([1, 'foo']))
224+
>x44 : readonly [true, number, string]
225+
>f4(true, ...([1, 'foo'])) : readonly [true, number, string]
226+
>f4 : <const T extends readonly unknown[]>(...args: T) => T
227+
>true : true
228+
>...([1, 'foo']) : string | number
229+
>([1, 'foo']) : [number, string]
230+
>[1, 'foo'] : [number, string]
122231
>1 : 1
123232
>'foo' : "foo"
124233

@@ -137,7 +246,7 @@ action.run(...[100, 'foo']) // error
137246
>action : IAction
138247
>run : (event?: unknown) => unknown
139248
>...[100, 'foo'] : string | number
140-
>[100, 'foo'] : readonly [number, string]
249+
>[100, 'foo'] : [number, string]
141250
>100 : 100
142251
>'foo' : "foo"
143252

0 commit comments

Comments
 (0)