Skip to content

Commit d681520

Browse files
authored
Fixed array expression spreads into variadic const calls (#52845)
1 parent 615a97b commit d681520

25 files changed

+467
-152
lines changed

src/compiler/checker.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29712,9 +29712,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2971229712
const elementFlags: ElementFlags[] = [];
2971329713
pushCachedContextualType(node);
2971429714
const inDestructuringPattern = isAssignmentTarget(node);
29715-
const inConstContext = isConstContext(node);
29715+
const isSpreadIntoCallOrNew = isSpreadElement(node.parent) && isCallOrNewExpression(node.parent.parent);
29716+
const inConstContext = isSpreadIntoCallOrNew || isConstContext(node);
2971629717
const contextualType = getApparentTypeOfContextualType(node, /*contextFlags*/ undefined);
29717-
const inTupleContext = !!contextualType && someType(contextualType, isTupleLikeType);
29718+
const inTupleContext = isSpreadIntoCallOrNew || !!contextualType && someType(contextualType, isTupleLikeType);
2971829719
let hasOmittedExpression = false;
2971929720
for (let i = 0; i < elementCount; i++) {
2972029721
const e = elements[i];
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
tests/cases/conformance/es6/spread/arraySpreadInCall.ts(21,12): error TS2554: Expected 0-1 arguments, but got 2.
2+
3+
4+
==== tests/cases/conformance/es6/spread/arraySpreadInCall.ts (1 errors) ====
5+
declare function f1(a: number, b: number, c: number, d: number, e: number, f: number): void;
6+
f1(1, 2, 3, 4, ...[5, 6]);
7+
f1(...[1], 2, 3, 4, 5, 6);
8+
f1(1, 2, ...[3, 4], 5, 6);
9+
f1(1, 2, ...[3], 4, ...[5, 6]);
10+
f1(...[1, 2], ...[3, 4], ...[5, 6]);
11+
12+
declare function f2<T extends unknown[]>(...args: T): T;
13+
const x21 = f2(...[1, 'foo'])
14+
const x22 = f2(true, ...[1, 'foo'])
15+
16+
declare function f3<T extends readonly unknown[]>(...args: T): T;
17+
const x31 = f3(...[1, 'foo'])
18+
const x32 = f3(true, ...[1, 'foo'])
19+
20+
// dicovered in #52845#issuecomment-1459132562
21+
interface IAction {
22+
run(event?: unknown): unknown;
23+
}
24+
declare const action: IAction
25+
action.run(...[100, 'foo']) // error
26+
~~~~~~~~~~~~~~~
27+
!!! error TS2554: Expected 0-1 arguments, but got 2.
28+
29+
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
=== tests/cases/conformance/es6/spread/arraySpreadInCall.ts ===
2+
declare function f1(a: number, b: number, c: number, d: number, e: number, f: number): void;
3+
>f1 : Symbol(f1, Decl(arraySpreadInCall.ts, 0, 0))
4+
>a : Symbol(a, Decl(arraySpreadInCall.ts, 0, 20))
5+
>b : Symbol(b, Decl(arraySpreadInCall.ts, 0, 30))
6+
>c : Symbol(c, Decl(arraySpreadInCall.ts, 0, 41))
7+
>d : Symbol(d, Decl(arraySpreadInCall.ts, 0, 52))
8+
>e : Symbol(e, Decl(arraySpreadInCall.ts, 0, 63))
9+
>f : Symbol(f, Decl(arraySpreadInCall.ts, 0, 74))
10+
11+
f1(1, 2, 3, 4, ...[5, 6]);
12+
>f1 : Symbol(f1, Decl(arraySpreadInCall.ts, 0, 0))
13+
14+
f1(...[1], 2, 3, 4, 5, 6);
15+
>f1 : Symbol(f1, Decl(arraySpreadInCall.ts, 0, 0))
16+
17+
f1(1, 2, ...[3, 4], 5, 6);
18+
>f1 : Symbol(f1, Decl(arraySpreadInCall.ts, 0, 0))
19+
20+
f1(1, 2, ...[3], 4, ...[5, 6]);
21+
>f1 : Symbol(f1, Decl(arraySpreadInCall.ts, 0, 0))
22+
23+
f1(...[1, 2], ...[3, 4], ...[5, 6]);
24+
>f1 : Symbol(f1, Decl(arraySpreadInCall.ts, 0, 0))
25+
26+
declare function f2<T extends unknown[]>(...args: T): T;
27+
>f2 : Symbol(f2, Decl(arraySpreadInCall.ts, 5, 36))
28+
>T : Symbol(T, Decl(arraySpreadInCall.ts, 7, 20))
29+
>args : Symbol(args, Decl(arraySpreadInCall.ts, 7, 41))
30+
>T : Symbol(T, Decl(arraySpreadInCall.ts, 7, 20))
31+
>T : Symbol(T, Decl(arraySpreadInCall.ts, 7, 20))
32+
33+
const x21 = f2(...[1, 'foo'])
34+
>x21 : Symbol(x21, Decl(arraySpreadInCall.ts, 8, 5))
35+
>f2 : Symbol(f2, Decl(arraySpreadInCall.ts, 5, 36))
36+
37+
const x22 = f2(true, ...[1, 'foo'])
38+
>x22 : Symbol(x22, Decl(arraySpreadInCall.ts, 9, 5))
39+
>f2 : Symbol(f2, Decl(arraySpreadInCall.ts, 5, 36))
40+
41+
declare function f3<T extends readonly unknown[]>(...args: T): T;
42+
>f3 : Symbol(f3, Decl(arraySpreadInCall.ts, 9, 35))
43+
>T : Symbol(T, Decl(arraySpreadInCall.ts, 11, 20))
44+
>args : Symbol(args, Decl(arraySpreadInCall.ts, 11, 50))
45+
>T : Symbol(T, Decl(arraySpreadInCall.ts, 11, 20))
46+
>T : Symbol(T, Decl(arraySpreadInCall.ts, 11, 20))
47+
48+
const x31 = f3(...[1, 'foo'])
49+
>x31 : Symbol(x31, Decl(arraySpreadInCall.ts, 12, 5))
50+
>f3 : Symbol(f3, Decl(arraySpreadInCall.ts, 9, 35))
51+
52+
const x32 = f3(true, ...[1, 'foo'])
53+
>x32 : Symbol(x32, Decl(arraySpreadInCall.ts, 13, 5))
54+
>f3 : Symbol(f3, Decl(arraySpreadInCall.ts, 9, 35))
55+
56+
// dicovered in #52845#issuecomment-1459132562
57+
interface IAction {
58+
>IAction : Symbol(IAction, Decl(arraySpreadInCall.ts, 13, 35))
59+
60+
run(event?: unknown): unknown;
61+
>run : Symbol(IAction.run, Decl(arraySpreadInCall.ts, 16, 19))
62+
>event : Symbol(event, Decl(arraySpreadInCall.ts, 17, 8))
63+
}
64+
declare const action: IAction
65+
>action : Symbol(action, Decl(arraySpreadInCall.ts, 19, 13))
66+
>IAction : Symbol(IAction, Decl(arraySpreadInCall.ts, 13, 35))
67+
68+
action.run(...[100, 'foo']) // error
69+
>action.run : Symbol(IAction.run, Decl(arraySpreadInCall.ts, 16, 19))
70+
>action : Symbol(action, Decl(arraySpreadInCall.ts, 19, 13))
71+
>run : Symbol(IAction.run, Decl(arraySpreadInCall.ts, 16, 19))
72+
73+
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
=== tests/cases/conformance/es6/spread/arraySpreadInCall.ts ===
2+
declare function f1(a: number, b: number, c: number, d: number, e: number, f: number): void;
3+
>f1 : (a: number, b: number, c: number, d: number, e: number, f: number) => void
4+
>a : number
5+
>b : number
6+
>c : number
7+
>d : number
8+
>e : number
9+
>f : number
10+
11+
f1(1, 2, 3, 4, ...[5, 6]);
12+
>f1(1, 2, 3, 4, ...[5, 6]) : void
13+
>f1 : (a: number, b: number, c: number, d: number, e: number, f: number) => void
14+
>1 : 1
15+
>2 : 2
16+
>3 : 3
17+
>4 : 4
18+
>...[5, 6] : number
19+
>[5, 6] : readonly [number, number]
20+
>5 : 5
21+
>6 : 6
22+
23+
f1(...[1], 2, 3, 4, 5, 6);
24+
>f1(...[1], 2, 3, 4, 5, 6) : void
25+
>f1 : (a: number, b: number, c: number, d: number, e: number, f: number) => void
26+
>...[1] : number
27+
>[1] : readonly [number]
28+
>1 : 1
29+
>2 : 2
30+
>3 : 3
31+
>4 : 4
32+
>5 : 5
33+
>6 : 6
34+
35+
f1(1, 2, ...[3, 4], 5, 6);
36+
>f1(1, 2, ...[3, 4], 5, 6) : void
37+
>f1 : (a: number, b: number, c: number, d: number, e: number, f: number) => void
38+
>1 : 1
39+
>2 : 2
40+
>...[3, 4] : number
41+
>[3, 4] : readonly [number, number]
42+
>3 : 3
43+
>4 : 4
44+
>5 : 5
45+
>6 : 6
46+
47+
f1(1, 2, ...[3], 4, ...[5, 6]);
48+
>f1(1, 2, ...[3], 4, ...[5, 6]) : void
49+
>f1 : (a: number, b: number, c: number, d: number, e: number, f: number) => void
50+
>1 : 1
51+
>2 : 2
52+
>...[3] : number
53+
>[3] : readonly [number]
54+
>3 : 3
55+
>4 : 4
56+
>...[5, 6] : number
57+
>[5, 6] : readonly [number, number]
58+
>5 : 5
59+
>6 : 6
60+
61+
f1(...[1, 2], ...[3, 4], ...[5, 6]);
62+
>f1(...[1, 2], ...[3, 4], ...[5, 6]) : void
63+
>f1 : (a: number, b: number, c: number, d: number, e: number, f: number) => void
64+
>...[1, 2] : number
65+
>[1, 2] : readonly [number, number]
66+
>1 : 1
67+
>2 : 2
68+
>...[3, 4] : number
69+
>[3, 4] : readonly [number, number]
70+
>3 : 3
71+
>4 : 4
72+
>...[5, 6] : number
73+
>[5, 6] : readonly [number, number]
74+
>5 : 5
75+
>6 : 6
76+
77+
declare function f2<T extends unknown[]>(...args: T): T;
78+
>f2 : <T extends unknown[]>(...args: T) => T
79+
>args : T
80+
81+
const x21 = f2(...[1, 'foo'])
82+
>x21 : [number, string]
83+
>f2(...[1, 'foo']) : [number, string]
84+
>f2 : <T extends unknown[]>(...args: T) => T
85+
>...[1, 'foo'] : string | number
86+
>[1, 'foo'] : readonly [number, string]
87+
>1 : 1
88+
>'foo' : "foo"
89+
90+
const x22 = f2(true, ...[1, 'foo'])
91+
>x22 : [boolean, number, string]
92+
>f2(true, ...[1, 'foo']) : [boolean, number, string]
93+
>f2 : <T extends unknown[]>(...args: T) => T
94+
>true : true
95+
>...[1, 'foo'] : string | number
96+
>[1, 'foo'] : readonly [number, string]
97+
>1 : 1
98+
>'foo' : "foo"
99+
100+
declare function f3<T extends readonly unknown[]>(...args: T): T;
101+
>f3 : <T extends readonly unknown[]>(...args: T) => T
102+
>args : T
103+
104+
const x31 = f3(...[1, 'foo'])
105+
>x31 : [number, string]
106+
>f3(...[1, 'foo']) : [number, string]
107+
>f3 : <T extends readonly unknown[]>(...args: T) => T
108+
>...[1, 'foo'] : string | number
109+
>[1, 'foo'] : readonly [number, string]
110+
>1 : 1
111+
>'foo' : "foo"
112+
113+
const x32 = f3(true, ...[1, 'foo'])
114+
>x32 : [boolean, number, string]
115+
>f3(true, ...[1, 'foo']) : [boolean, number, string]
116+
>f3 : <T extends readonly unknown[]>(...args: T) => T
117+
>true : true
118+
>...[1, 'foo'] : string | number
119+
>[1, 'foo'] : readonly [number, string]
120+
>1 : 1
121+
>'foo' : "foo"
122+
123+
// dicovered in #52845#issuecomment-1459132562
124+
interface IAction {
125+
run(event?: unknown): unknown;
126+
>run : (event?: unknown) => unknown
127+
>event : unknown
128+
}
129+
declare const action: IAction
130+
>action : IAction
131+
132+
action.run(...[100, 'foo']) // error
133+
>action.run(...[100, 'foo']) : unknown
134+
>action.run : (event?: unknown) => unknown
135+
>action : IAction
136+
>run : (event?: unknown) => unknown
137+
>...[100, 'foo'] : string | number
138+
>[100, 'foo'] : readonly [number, string]
139+
>100 : 100
140+
>'foo' : "foo"
141+
142+

tests/baselines/reference/callChain.types

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ o1?.(...[1, 2]);
1616
>o1?.(...[1, 2]) : number | undefined
1717
>o1 : ((...args: any[]) => number) | undefined
1818
>...[1, 2] : number
19-
>[1, 2] : number[]
19+
>[1, 2] : readonly [number, number]
2020
>1 : 1
2121
>2 : 2
2222

@@ -25,7 +25,7 @@ o1?.(1, ...[2, 3], 4);
2525
>o1 : ((...args: any[]) => number) | undefined
2626
>1 : 1
2727
>...[2, 3] : number
28-
>[2, 3] : number[]
28+
>[2, 3] : readonly [number, number]
2929
>2 : 2
3030
>3 : 3
3131
>4 : 4
@@ -54,7 +54,7 @@ o2?.b(...[1, 2]);
5454
>o2 : { b: (...args: any[]) => number; } | undefined
5555
>b : ((...args: any[]) => number) | undefined
5656
>...[1, 2] : number
57-
>[1, 2] : number[]
57+
>[1, 2] : readonly [number, number]
5858
>1 : 1
5959
>2 : 2
6060

@@ -65,7 +65,7 @@ o2?.b(1, ...[2, 3], 4);
6565
>b : ((...args: any[]) => number) | undefined
6666
>1 : 1
6767
>...[2, 3] : number
68-
>[2, 3] : number[]
68+
>[2, 3] : readonly [number, number]
6969
>2 : 2
7070
>3 : 3
7171
>4 : 4
@@ -89,7 +89,7 @@ o2?.["b"](...[1, 2]);
8989
>o2 : { b: (...args: any[]) => number; } | undefined
9090
>"b" : "b"
9191
>...[1, 2] : number
92-
>[1, 2] : number[]
92+
>[1, 2] : readonly [number, number]
9393
>1 : 1
9494
>2 : 2
9595

@@ -100,7 +100,7 @@ o2?.["b"](1, ...[2, 3], 4);
100100
>"b" : "b"
101101
>1 : 1
102102
>...[2, 3] : number
103-
>[2, 3] : number[]
103+
>[2, 3] : readonly [number, number]
104104
>2 : 2
105105
>3 : 3
106106
>4 : 4
@@ -135,7 +135,7 @@ o3.b?.(...[1, 2]).c;
135135
>o3 : { b: ((...args: any[]) => { c: string; }) | undefined; }
136136
>b : ((...args: any[]) => { c: string; }) | undefined
137137
>...[1, 2] : number
138-
>[1, 2] : number[]
138+
>[1, 2] : readonly [number, number]
139139
>1 : 1
140140
>2 : 2
141141
>c : string | undefined
@@ -148,7 +148,7 @@ o3.b?.(1, ...[2, 3], 4).c;
148148
>b : ((...args: any[]) => { c: string; }) | undefined
149149
>1 : 1
150150
>...[2, 3] : number
151-
>[2, 3] : number[]
151+
>[2, 3] : readonly [number, number]
152152
>2 : 2
153153
>3 : 3
154154
>4 : 4
@@ -178,7 +178,7 @@ o3.b?.(...[1, 2])["c"];
178178
>o3 : { b: ((...args: any[]) => { c: string; }) | undefined; }
179179
>b : ((...args: any[]) => { c: string; }) | undefined
180180
>...[1, 2] : number
181-
>[1, 2] : number[]
181+
>[1, 2] : readonly [number, number]
182182
>1 : 1
183183
>2 : 2
184184
>"c" : "c"
@@ -191,7 +191,7 @@ o3.b?.(1, ...[2, 3], 4)["c"];
191191
>b : ((...args: any[]) => { c: string; }) | undefined
192192
>1 : 1
193193
>...[2, 3] : number
194-
>[2, 3] : number[]
194+
>[2, 3] : readonly [number, number]
195195
>2 : 2
196196
>3 : 3
197197
>4 : 4
@@ -221,7 +221,7 @@ o3["b"]?.(...[1, 2]).c;
221221
>o3 : { b: ((...args: any[]) => { c: string; }) | undefined; }
222222
>"b" : "b"
223223
>...[1, 2] : number
224-
>[1, 2] : number[]
224+
>[1, 2] : readonly [number, number]
225225
>1 : 1
226226
>2 : 2
227227
>c : string | undefined
@@ -234,7 +234,7 @@ o3["b"]?.(1, ...[2, 3], 4).c;
234234
>"b" : "b"
235235
>1 : 1
236236
>...[2, 3] : number
237-
>[2, 3] : number[]
237+
>[2, 3] : readonly [number, number]
238238
>2 : 2
239239
>3 : 3
240240
>4 : 4

tests/baselines/reference/callWithSpread.types

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ xa[1].foo(1, 2, ...a, "abc");
267267
>1 : 1
268268
>foo : (x: number, y: number, ...z: string[]) => X
269269
>...[1, 2, "abc"] : string | number
270-
>[1, 2, "abc"] : (string | number)[]
270+
>[1, 2, "abc"] : readonly [number, number, string]
271271
>1 : 1
272272
>2 : 2
273273
>"abc" : "abc"

tests/baselines/reference/callWithSpreadES6.types

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ xa[1].foo(1, 2, ...a, "abc");
159159
>1 : 1
160160
>foo : (x: number, y: number, ...z: string[]) => any
161161
>...[1, 2, "abc"] : string | number
162-
>[1, 2, "abc"] : (string | number)[]
162+
>[1, 2, "abc"] : readonly [number, number, string]
163163
>1 : 1
164164
>2 : 2
165165
>"abc" : "abc"

0 commit comments

Comments
 (0)