Skip to content

Commit cfb7fff

Browse files
committed
Allow calls ending with unions of tuples
Previously, only calls with tuples were allowed, not unions of tuples. For example, this already works: ``` f(string, [number, string], string) ==> f(string, number, string, string) ``` But this does not: ``` f(string, [string] | [number, number]) ==> (f, string, string | number, number | undefined) ``` This PR allows union types like these *as the last argument*. It's possible to allow them anywhere, but quite a bit more complicated. And the code is already complicated enough: getEffectiveCallArguments now needs to return the minimum number of arguments as well as the argument list (which is the maximum number of arguments). Also, this transformation should not happen when the tuple union argument is passed to a tuple union rest parameter: `[number] | [string]` is assignable to `[number] | [string]` but the transformed `number | string` is not. Checking for this requires passing around even more information. Bottom line: I'm not sure the complexity is worth the new code. However, if this is a good idea, there are 3 things that need to be cleaned up: 1. More precise error messages--maybe. Right now error messages are reported in terms of the maximum number of arguments: 2. Allow tuples with trailing `...T` types. Not done or tested, but straightfoward. 3. Find a more elegant way to return the minimum number of arguments. Fixes microsoft#42508 Supercedes microsoft#43882, but does less than half of that PR, in less than half the code.
1 parent cbf3c63 commit cfb7fff

File tree

6 files changed

+464
-51
lines changed

6 files changed

+464
-51
lines changed

src/compiler/checker.ts

Lines changed: 95 additions & 51 deletions
Large diffs are not rendered by default.
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
callWithSpread6.ts(15,1): error TS2554: Expected 4 arguments, but got 3.
2+
callWithSpread6.ts(17,19): error TS2554: Expected 1-4 arguments, but got 5.
3+
callWithSpread6.ts(18,10): error TS2556: A spread argument must either have a tuple type or be passed to a rest parameter.
4+
callWithSpread6.ts(20,1): error TS2555: Expected at least 2 arguments, but got 1.
5+
callWithSpread6.ts(22,3): error TS2556: A spread argument must either have a tuple type or be passed to a rest parameter.
6+
callWithSpread6.ts(23,1): error TS2555: Expected at least 3 arguments, but got 1.
7+
callWithSpread6.ts(24,1): error TS2555: Expected at least 3 arguments, but got 2.
8+
9+
10+
==== callWithSpread6.ts (7 errors) ====
11+
declare const n: number
12+
declare const nntnnnt: [number, number] | [number, number, number]
13+
declare const ntnnnt: [number] | [number, number, number]
14+
declare const ntnnnut: [number] | [number, number, number?]
15+
declare function setHours(a: number, b?: number, c?: number, d?: number): number
16+
declare function setHoursStrict(a: number, b: number, c: number, d: number): number
17+
declare function f(a: number, b: number, ...c: number[]): number
18+
declare function g(a: number, b?: number, ...c: number[]): number
19+
declare function h(a: number, b: number, c: number, ...d: number[]): number
20+
21+
setHours(...nntnnnt)
22+
setHours(...ntnnnt)
23+
setHours(...ntnnnut)
24+
setHours(n, n, ...nntnnnt)
25+
setHoursStrict(n, ...nntnnnt)
26+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
27+
!!! error TS2554: Expected 4 arguments, but got 3.
28+
!!! related TS6210 callWithSpread6.ts:6:66: An argument for 'd' was not provided.
29+
setHoursStrict(n, n, ...nntnnnt)
30+
setHours(n, n, n, ...nntnnnt)
31+
~~~~~~~~~~
32+
!!! error TS2554: Expected 1-4 arguments, but got 5.
33+
setHours(...nntnnnt, n)
34+
~~~~~~~~~~
35+
!!! error TS2556: A spread argument must either have a tuple type or be passed to a rest parameter.
36+
37+
f(...ntnnnt)
38+
~~~~~~~~~~~~
39+
!!! error TS2555: Expected at least 2 arguments, but got 1.
40+
!!! related TS6210 callWithSpread6.ts:7:31: An argument for 'b' was not provided.
41+
f(...nntnnnt)
42+
f(...nntnnnt, n)
43+
~~~~~~~~~~
44+
!!! error TS2556: A spread argument must either have a tuple type or be passed to a rest parameter.
45+
h(...ntnnnt)
46+
~~~~~~~~~~~~
47+
!!! error TS2555: Expected at least 3 arguments, but got 1.
48+
!!! related TS6210 callWithSpread6.ts:9:31: An argument for 'b' was not provided.
49+
h(...nntnnnt)
50+
~~~~~~~~~~~~~
51+
!!! error TS2555: Expected at least 3 arguments, but got 2.
52+
!!! related TS6210 callWithSpread6.ts:9:42: An argument for 'c' was not provided.
53+
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
//// [tests/cases/conformance/expressions/functionCalls/callWithSpread6.ts] ////
2+
3+
//// [callWithSpread6.ts]
4+
declare const n: number
5+
declare const nntnnnt: [number, number] | [number, number, number]
6+
declare const ntnnnt: [number] | [number, number, number]
7+
declare const ntnnnut: [number] | [number, number, number?]
8+
declare function setHours(a: number, b?: number, c?: number, d?: number): number
9+
declare function setHoursStrict(a: number, b: number, c: number, d: number): number
10+
declare function f(a: number, b: number, ...c: number[]): number
11+
declare function g(a: number, b?: number, ...c: number[]): number
12+
declare function h(a: number, b: number, c: number, ...d: number[]): number
13+
14+
setHours(...nntnnnt)
15+
setHours(...ntnnnt)
16+
setHours(...ntnnnut)
17+
setHours(n, n, ...nntnnnt)
18+
setHoursStrict(n, ...nntnnnt)
19+
setHoursStrict(n, n, ...nntnnnt)
20+
setHours(n, n, n, ...nntnnnt)
21+
setHours(...nntnnnt, n)
22+
23+
f(...ntnnnt)
24+
f(...nntnnnt)
25+
f(...nntnnnt, n)
26+
h(...ntnnnt)
27+
h(...nntnnnt)
28+
29+
30+
//// [callWithSpread6.js]
31+
"use strict";
32+
setHours(...nntnnnt);
33+
setHours(...ntnnnt);
34+
setHours(...ntnnnut);
35+
setHours(n, n, ...nntnnnt);
36+
setHoursStrict(n, ...nntnnnt);
37+
setHoursStrict(n, n, ...nntnnnt);
38+
setHours(n, n, n, ...nntnnnt);
39+
setHours(...nntnnnt, n);
40+
f(...ntnnnt);
41+
f(...nntnnnt);
42+
f(...nntnnnt, n);
43+
h(...ntnnnt);
44+
h(...nntnnnt);
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
//// [tests/cases/conformance/expressions/functionCalls/callWithSpread6.ts] ////
2+
3+
=== callWithSpread6.ts ===
4+
declare const n: number
5+
>n : Symbol(n, Decl(callWithSpread6.ts, 0, 13))
6+
7+
declare const nntnnnt: [number, number] | [number, number, number]
8+
>nntnnnt : Symbol(nntnnnt, Decl(callWithSpread6.ts, 1, 13))
9+
10+
declare const ntnnnt: [number] | [number, number, number]
11+
>ntnnnt : Symbol(ntnnnt, Decl(callWithSpread6.ts, 2, 13))
12+
13+
declare const ntnnnut: [number] | [number, number, number?]
14+
>ntnnnut : Symbol(ntnnnut, Decl(callWithSpread6.ts, 3, 13))
15+
16+
declare function setHours(a: number, b?: number, c?: number, d?: number): number
17+
>setHours : Symbol(setHours, Decl(callWithSpread6.ts, 3, 59))
18+
>a : Symbol(a, Decl(callWithSpread6.ts, 4, 26))
19+
>b : Symbol(b, Decl(callWithSpread6.ts, 4, 36))
20+
>c : Symbol(c, Decl(callWithSpread6.ts, 4, 48))
21+
>d : Symbol(d, Decl(callWithSpread6.ts, 4, 60))
22+
23+
declare function setHoursStrict(a: number, b: number, c: number, d: number): number
24+
>setHoursStrict : Symbol(setHoursStrict, Decl(callWithSpread6.ts, 4, 80))
25+
>a : Symbol(a, Decl(callWithSpread6.ts, 5, 32))
26+
>b : Symbol(b, Decl(callWithSpread6.ts, 5, 42))
27+
>c : Symbol(c, Decl(callWithSpread6.ts, 5, 53))
28+
>d : Symbol(d, Decl(callWithSpread6.ts, 5, 64))
29+
30+
declare function f(a: number, b: number, ...c: number[]): number
31+
>f : Symbol(f, Decl(callWithSpread6.ts, 5, 83))
32+
>a : Symbol(a, Decl(callWithSpread6.ts, 6, 19))
33+
>b : Symbol(b, Decl(callWithSpread6.ts, 6, 29))
34+
>c : Symbol(c, Decl(callWithSpread6.ts, 6, 40))
35+
36+
declare function g(a: number, b?: number, ...c: number[]): number
37+
>g : Symbol(g, Decl(callWithSpread6.ts, 6, 64))
38+
>a : Symbol(a, Decl(callWithSpread6.ts, 7, 19))
39+
>b : Symbol(b, Decl(callWithSpread6.ts, 7, 29))
40+
>c : Symbol(c, Decl(callWithSpread6.ts, 7, 41))
41+
42+
declare function h(a: number, b: number, c: number, ...d: number[]): number
43+
>h : Symbol(h, Decl(callWithSpread6.ts, 7, 65))
44+
>a : Symbol(a, Decl(callWithSpread6.ts, 8, 19))
45+
>b : Symbol(b, Decl(callWithSpread6.ts, 8, 29))
46+
>c : Symbol(c, Decl(callWithSpread6.ts, 8, 40))
47+
>d : Symbol(d, Decl(callWithSpread6.ts, 8, 51))
48+
49+
setHours(...nntnnnt)
50+
>setHours : Symbol(setHours, Decl(callWithSpread6.ts, 3, 59))
51+
>nntnnnt : Symbol(nntnnnt, Decl(callWithSpread6.ts, 1, 13))
52+
53+
setHours(...ntnnnt)
54+
>setHours : Symbol(setHours, Decl(callWithSpread6.ts, 3, 59))
55+
>ntnnnt : Symbol(ntnnnt, Decl(callWithSpread6.ts, 2, 13))
56+
57+
setHours(...ntnnnut)
58+
>setHours : Symbol(setHours, Decl(callWithSpread6.ts, 3, 59))
59+
>ntnnnut : Symbol(ntnnnut, Decl(callWithSpread6.ts, 3, 13))
60+
61+
setHours(n, n, ...nntnnnt)
62+
>setHours : Symbol(setHours, Decl(callWithSpread6.ts, 3, 59))
63+
>n : Symbol(n, Decl(callWithSpread6.ts, 0, 13))
64+
>n : Symbol(n, Decl(callWithSpread6.ts, 0, 13))
65+
>nntnnnt : Symbol(nntnnnt, Decl(callWithSpread6.ts, 1, 13))
66+
67+
setHoursStrict(n, ...nntnnnt)
68+
>setHoursStrict : Symbol(setHoursStrict, Decl(callWithSpread6.ts, 4, 80))
69+
>n : Symbol(n, Decl(callWithSpread6.ts, 0, 13))
70+
>nntnnnt : Symbol(nntnnnt, Decl(callWithSpread6.ts, 1, 13))
71+
72+
setHoursStrict(n, n, ...nntnnnt)
73+
>setHoursStrict : Symbol(setHoursStrict, Decl(callWithSpread6.ts, 4, 80))
74+
>n : Symbol(n, Decl(callWithSpread6.ts, 0, 13))
75+
>n : Symbol(n, Decl(callWithSpread6.ts, 0, 13))
76+
>nntnnnt : Symbol(nntnnnt, Decl(callWithSpread6.ts, 1, 13))
77+
78+
setHours(n, n, n, ...nntnnnt)
79+
>setHours : Symbol(setHours, Decl(callWithSpread6.ts, 3, 59))
80+
>n : Symbol(n, Decl(callWithSpread6.ts, 0, 13))
81+
>n : Symbol(n, Decl(callWithSpread6.ts, 0, 13))
82+
>n : Symbol(n, Decl(callWithSpread6.ts, 0, 13))
83+
>nntnnnt : Symbol(nntnnnt, Decl(callWithSpread6.ts, 1, 13))
84+
85+
setHours(...nntnnnt, n)
86+
>setHours : Symbol(setHours, Decl(callWithSpread6.ts, 3, 59))
87+
>nntnnnt : Symbol(nntnnnt, Decl(callWithSpread6.ts, 1, 13))
88+
>n : Symbol(n, Decl(callWithSpread6.ts, 0, 13))
89+
90+
f(...ntnnnt)
91+
>f : Symbol(f, Decl(callWithSpread6.ts, 5, 83))
92+
>ntnnnt : Symbol(ntnnnt, Decl(callWithSpread6.ts, 2, 13))
93+
94+
f(...nntnnnt)
95+
>f : Symbol(f, Decl(callWithSpread6.ts, 5, 83))
96+
>nntnnnt : Symbol(nntnnnt, Decl(callWithSpread6.ts, 1, 13))
97+
98+
f(...nntnnnt, n)
99+
>f : Symbol(f, Decl(callWithSpread6.ts, 5, 83))
100+
>nntnnnt : Symbol(nntnnnt, Decl(callWithSpread6.ts, 1, 13))
101+
>n : Symbol(n, Decl(callWithSpread6.ts, 0, 13))
102+
103+
h(...ntnnnt)
104+
>h : Symbol(h, Decl(callWithSpread6.ts, 7, 65))
105+
>ntnnnt : Symbol(ntnnnt, Decl(callWithSpread6.ts, 2, 13))
106+
107+
h(...nntnnnt)
108+
>h : Symbol(h, Decl(callWithSpread6.ts, 7, 65))
109+
>nntnnnt : Symbol(nntnnnt, Decl(callWithSpread6.ts, 1, 13))
110+
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
//// [tests/cases/conformance/expressions/functionCalls/callWithSpread6.ts] ////
2+
3+
=== callWithSpread6.ts ===
4+
declare const n: number
5+
>n : number
6+
7+
declare const nntnnnt: [number, number] | [number, number, number]
8+
>nntnnnt : [number, number] | [number, number, number]
9+
10+
declare const ntnnnt: [number] | [number, number, number]
11+
>ntnnnt : [number, number, number] | [number]
12+
13+
declare const ntnnnut: [number] | [number, number, number?]
14+
>ntnnnut : [number] | [number, number, (number | undefined)?]
15+
16+
declare function setHours(a: number, b?: number, c?: number, d?: number): number
17+
>setHours : (a: number, b?: number, c?: number, d?: number) => number
18+
>a : number
19+
>b : number | undefined
20+
>c : number | undefined
21+
>d : number | undefined
22+
23+
declare function setHoursStrict(a: number, b: number, c: number, d: number): number
24+
>setHoursStrict : (a: number, b: number, c: number, d: number) => number
25+
>a : number
26+
>b : number
27+
>c : number
28+
>d : number
29+
30+
declare function f(a: number, b: number, ...c: number[]): number
31+
>f : (a: number, b: number, ...c: number[]) => number
32+
>a : number
33+
>b : number
34+
>c : number[]
35+
36+
declare function g(a: number, b?: number, ...c: number[]): number
37+
>g : (a: number, b?: number, ...c: number[]) => number
38+
>a : number
39+
>b : number | undefined
40+
>c : number[]
41+
42+
declare function h(a: number, b: number, c: number, ...d: number[]): number
43+
>h : (a: number, b: number, c: number, ...d: number[]) => number
44+
>a : number
45+
>b : number
46+
>c : number
47+
>d : number[]
48+
49+
setHours(...nntnnnt)
50+
>setHours(...nntnnnt) : number
51+
>setHours : (a: number, b?: number | undefined, c?: number | undefined, d?: number | undefined) => number
52+
>...nntnnnt : number
53+
>nntnnnt : [number, number] | [number, number, number]
54+
55+
setHours(...ntnnnt)
56+
>setHours(...ntnnnt) : number
57+
>setHours : (a: number, b?: number | undefined, c?: number | undefined, d?: number | undefined) => number
58+
>...ntnnnt : number
59+
>ntnnnt : [number, number, number] | [number]
60+
61+
setHours(...ntnnnut)
62+
>setHours(...ntnnnut) : number
63+
>setHours : (a: number, b?: number | undefined, c?: number | undefined, d?: number | undefined) => number
64+
>...ntnnnut : number | undefined
65+
>ntnnnut : [number] | [number, number, (number | undefined)?]
66+
67+
setHours(n, n, ...nntnnnt)
68+
>setHours(n, n, ...nntnnnt) : number
69+
>setHours : (a: number, b?: number | undefined, c?: number | undefined, d?: number | undefined) => number
70+
>n : number
71+
>n : number
72+
>...nntnnnt : number
73+
>nntnnnt : [number, number] | [number, number, number]
74+
75+
setHoursStrict(n, ...nntnnnt)
76+
>setHoursStrict(n, ...nntnnnt) : number
77+
>setHoursStrict : (a: number, b: number, c: number, d: number) => number
78+
>n : number
79+
>...nntnnnt : number
80+
>nntnnnt : [number, number] | [number, number, number]
81+
82+
setHoursStrict(n, n, ...nntnnnt)
83+
>setHoursStrict(n, n, ...nntnnnt) : number
84+
>setHoursStrict : (a: number, b: number, c: number, d: number) => number
85+
>n : number
86+
>n : number
87+
>...nntnnnt : number
88+
>nntnnnt : [number, number] | [number, number, number]
89+
90+
setHours(n, n, n, ...nntnnnt)
91+
>setHours(n, n, n, ...nntnnnt) : number
92+
>setHours : (a: number, b?: number | undefined, c?: number | undefined, d?: number | undefined) => number
93+
>n : number
94+
>n : number
95+
>n : number
96+
>...nntnnnt : number
97+
>nntnnnt : [number, number] | [number, number, number]
98+
99+
setHours(...nntnnnt, n)
100+
>setHours(...nntnnnt, n) : number
101+
>setHours : (a: number, b?: number | undefined, c?: number | undefined, d?: number | undefined) => number
102+
>...nntnnnt : number
103+
>nntnnnt : [number, number] | [number, number, number]
104+
>n : number
105+
106+
f(...ntnnnt)
107+
>f(...ntnnnt) : number
108+
>f : (a: number, b: number, ...c: number[]) => number
109+
>...ntnnnt : number
110+
>ntnnnt : [number, number, number] | [number]
111+
112+
f(...nntnnnt)
113+
>f(...nntnnnt) : number
114+
>f : (a: number, b: number, ...c: number[]) => number
115+
>...nntnnnt : number
116+
>nntnnnt : [number, number] | [number, number, number]
117+
118+
f(...nntnnnt, n)
119+
>f(...nntnnnt, n) : number
120+
>f : (a: number, b: number, ...c: number[]) => number
121+
>...nntnnnt : number
122+
>nntnnnt : [number, number] | [number, number, number]
123+
>n : number
124+
125+
h(...ntnnnt)
126+
>h(...ntnnnt) : number
127+
>h : (a: number, b: number, c: number, ...d: number[]) => number
128+
>...ntnnnt : number
129+
>ntnnnt : [number, number, number] | [number]
130+
131+
h(...nntnnnt)
132+
>h(...nntnnnt) : number
133+
>h : (a: number, b: number, c: number, ...d: number[]) => number
134+
>...nntnnnt : number
135+
>nntnnnt : [number, number] | [number, number, number]
136+
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// @strict: true
2+
// @target: esnext
3+
declare const n: number
4+
declare const nntnnnt: [number, number] | [number, number, number]
5+
declare const ntnnnt: [number] | [number, number, number]
6+
declare const ntnnnut: [number] | [number, number, number?]
7+
declare function setHours(a: number, b?: number, c?: number, d?: number): number
8+
declare function setHoursStrict(a: number, b: number, c: number, d: number): number
9+
declare function f(a: number, b: number, ...c: number[]): number
10+
declare function g(a: number, b?: number, ...c: number[]): number
11+
declare function h(a: number, b: number, c: number, ...d: number[]): number
12+
13+
setHours(...nntnnnt)
14+
setHours(...ntnnnt)
15+
setHours(...ntnnnut)
16+
setHours(n, n, ...nntnnnt)
17+
setHoursStrict(n, ...nntnnnt)
18+
setHoursStrict(n, n, ...nntnnnt)
19+
setHours(n, n, n, ...nntnnnt)
20+
setHours(...nntnnnt, n)
21+
22+
f(...ntnnnt)
23+
f(...nntnnnt)
24+
f(...nntnnnt, n)
25+
h(...ntnnnt)
26+
h(...nntnnnt)

0 commit comments

Comments
 (0)