Skip to content

Commit f505150

Browse files
committed
Make hasCorrectArity handle tuples properly
This completes the work that started in PR #33069, and fixes #32835. There are probably two additional related changes that are needed to make this more complete: * Fix the code that composes the error message (see the first two `FIXME`s in `callWithSpread3.ts`). * Fix the code that checks the argument types (second two `FIXME`s). * There is also an error in `genericRestParameters1.ts` which changed but should not be an error in the first place. Added a `FIXME` there too. (Probably will work if the previous iterm is done.) In addition, `getEffectiveCallArguments` munges the arguments in case of a spread in the last argument which might be better to avoid. (I think that there are cases where it wouldn't work anyway, such as a spread of an array followed by a spread of an empty array.)
1 parent 0bf6c67 commit f505150

File tree

11 files changed

+450
-233
lines changed

11 files changed

+450
-233
lines changed

src/compiler/checker.ts

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -25051,13 +25051,12 @@ namespace ts {
2505125051
effectiveParameterCount = args.length === 0 ? effectiveParameterCount : 1; // class may have argumentless ctor functions - still resolve ctor and compare vs props member type
2505225052
effectiveMinimumArguments = Math.min(effectiveMinimumArguments, 1); // sfc may specify context argument - handled by framework and not typechecked
2505325053
}
25054+
else if (!node.arguments) {
25055+
// This only happens when we have something of the form: 'new C'
25056+
Debug.assert(node.kind === SyntaxKind.NewExpression);
25057+
return getMinArgumentCount(signature) === 0;
25058+
}
2505425059
else {
25055-
if (!node.arguments) {
25056-
// This only happens when we have something of the form: 'new C'
25057-
Debug.assert(node.kind === SyntaxKind.NewExpression);
25058-
return getMinArgumentCount(signature) === 0;
25059-
}
25060-
2506125060
argCount = signatureHelpTrailingComma ? args.length + 1 : args.length;
2506225061

2506325062
// If we are missing the close parenthesis, the call is incomplete.
@@ -25067,14 +25066,25 @@ namespace ts {
2506725066
const firstSpreadArgIndex = getSpreadArgumentIndex(args);
2506825067
if (firstSpreadArgIndex >= 0) {
2506925068
if (firstSpreadArgIndex === args.length - 1) {
25069+
// Special case, handles the munged arguments that we receive in case of a spread in the end (breaks the arg.expression below)
25070+
// (see below for code that starts with "const spreadArgument")
2507025071
return firstSpreadArgIndex >= getMinArgumentCount(signature) && (hasEffectiveRestParameter(signature) || firstSpreadArgIndex < getParameterCount(signature));
2507125072
}
2507225073

25073-
let totalCount = countSpreadArgumentLength(<SpreadElement>args[firstSpreadArgIndex]);
25074+
let totalCount = firstSpreadArgIndex; // count previous arguments
2507425075
for (let i = firstSpreadArgIndex; i < args.length; i++) {
25075-
totalCount += isSpreadArgument(args[i]) ? countSpreadArgumentLength(<SpreadElement>args[i]) : 1;
25076+
const arg = args[i];
25077+
if (!isSpreadArgument(arg)) {
25078+
totalCount += 1;
25079+
}
25080+
else {
25081+
const argType = flowLoopCount ? checkExpression((<SpreadElement>arg).expression) : checkExpressionCached((<SpreadElement>arg).expression);
25082+
totalCount += isTupleType(argType) ? getTypeArguments(argType).length
25083+
: isArrayType(argType) ? 0
25084+
: 1;
25085+
}
2507625086
}
25077-
return totalCount >= getMinArgumentCount(signature) && (hasEffectiveRestParameter(signature) || totalCount < getParameterCount(signature));
25087+
return totalCount >= getMinArgumentCount(signature) && (hasEffectiveRestParameter(signature) || totalCount <= getParameterCount(signature));
2507825088
}
2507925089
}
2508025090

@@ -25097,11 +25107,6 @@ namespace ts {
2509725107
return true;
2509825108
}
2509925109

25100-
function countSpreadArgumentLength(argment: SpreadElement): number {
25101-
const type = flowLoopCount ? checkExpression(argment.expression) : checkExpressionCached(argment.expression);
25102-
return isTupleType(type) ? getTypeArguments(type).length : 1;
25103-
}
25104-
2510525110
function hasCorrectTypeArgumentArity(signature: Signature, typeArguments: NodeArray<TypeNode> | undefined) {
2510625111
// If the user supplied type arguments, but the number of type arguments does not match
2510725112
// the declared number of type parameters, the call has an incorrect arity.
Lines changed: 62 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,75 @@
1-
tests/cases/conformance/expressions/functionCalls/callWithSpread3.ts(9,14): error TS2554: Expected 2 arguments, but got 3.
2-
tests/cases/conformance/expressions/functionCalls/callWithSpread3.ts(10,19): error TS2554: Expected 2 arguments, but got 5.
3-
tests/cases/conformance/expressions/functionCalls/callWithSpread3.ts(11,19): error TS2556: Expected 2 arguments, but got 4 or more.
4-
tests/cases/conformance/expressions/functionCalls/callWithSpread3.ts(12,19): error TS2556: Expected 2 arguments, but got 5 or more.
5-
tests/cases/conformance/expressions/functionCalls/callWithSpread3.ts(13,16): error TS2556: Expected 2 arguments, but got 1 or more.
6-
tests/cases/conformance/expressions/functionCalls/callWithSpread3.ts(14,9): error TS2554: Expected 2 arguments, but got 3.
1+
tests/cases/conformance/expressions/functionCalls/callWithSpread3.ts(14,10): error TS2554: Expected 2 arguments, but got 3.
2+
tests/cases/conformance/expressions/functionCalls/callWithSpread3.ts(15,15): error TS2554: Expected 2 arguments, but got 5.
3+
tests/cases/conformance/expressions/functionCalls/callWithSpread3.ts(16,15): error TS2556: Expected 2 arguments, but got 4 or more.
4+
tests/cases/conformance/expressions/functionCalls/callWithSpread3.ts(17,15): error TS2556: Expected 2 arguments, but got 5 or more.
5+
tests/cases/conformance/expressions/functionCalls/callWithSpread3.ts(18,12): error TS2556: Expected 2 arguments, but got 1 or more.
6+
tests/cases/conformance/expressions/functionCalls/callWithSpread3.ts(19,5): error TS2554: Expected 2 arguments, but got 3.
7+
tests/cases/conformance/expressions/functionCalls/callWithSpread3.ts(20,6): error TS2557: Expected at least 2 arguments, but got 0 or more.
8+
tests/cases/conformance/expressions/functionCalls/callWithSpread3.ts(21,6): error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'.
9+
tests/cases/conformance/expressions/functionCalls/callWithSpread3.ts(22,13): error TS2557: Expected at least 2 arguments, but got 1 or more.
10+
tests/cases/conformance/expressions/functionCalls/callWithSpread3.ts(23,13): error TS2557: Expected at least 2 arguments, but got 2 or more.
11+
tests/cases/conformance/expressions/functionCalls/callWithSpread3.ts(25,7): error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.
712

813

9-
==== tests/cases/conformance/expressions/functionCalls/callWithSpread3.ts (6 errors) ====
10-
declare function takeTwo(a: string, b: string): void;
11-
declare const t2: [string, string];
12-
declare const t3: [string, string, string];
13-
declare function takeTwoOrMore (a: string, b: string, ...c: string[]): void
14-
declare const t4: [string, string, ...string[]]
15-
declare const t5: string[]
14+
==== tests/cases/conformance/expressions/functionCalls/callWithSpread3.ts (11 errors) ====
15+
declare const s2: [string, string];
16+
declare const s3: [string, string, string];
17+
declare const s2_: [string, string, ...string[]];
18+
declare const s_: string[];
19+
declare const n_: number[];
20+
declare const s2n_: [string, string, ...number[]];
21+
22+
declare function fs2(a: string, b: string): void;
23+
declare function fs2_(a: string, b: string, ...c: string[]): void;
24+
declare function fs2n_(a: string, b: string, ...c: number[]): void;
25+
declare function fs5(a: string, b: string, c: string, d: string, e: string): void;
1626

1727
// error
18-
takeTwo('a', ...t2); // error on ...t2
19-
~~~~~
28+
fs2('a', ...s2); // error on ...s2
29+
~~~~~
2030
!!! error TS2554: Expected 2 arguments, but got 3.
21-
takeTwo('a', 'b', 'c', ...t2); // error on 'c' and ...t2
22-
~~~~~~~~~~
31+
fs2('a', 'b', 'c', ...s2); // error on 'c' and ...s2
32+
~~~~~~~~~~
2333
!!! error TS2554: Expected 2 arguments, but got 5.
24-
takeTwo('a', 'b', ...t2, 'c'); // error on ...t2 and 'c'
25-
~~~~~~~~~~
34+
fs2('a', 'b', ...s2, 'c'); // error on ...s2 and 'c'
35+
~~~~~~~~~~
2636
!!! error TS2556: Expected 2 arguments, but got 4 or more.
27-
takeTwo('a', 'b', 'c', ...t2, 'd'); // error on 'c', ...t2 and 'd'
28-
~~~~~~~~~~~~~~~
37+
fs2('a', 'b', 'c', ...s2, 'd'); // error on 'c', ...s2 and 'd'
38+
~~~~~~~~~~~~~~~
2939
!!! error TS2556: Expected 2 arguments, but got 5 or more.
30-
takeTwo(...t2, 'a'); // error on 'a'
31-
~~~
40+
fs2(...s2, 'a'); // error on 'a'
41+
~~~
3242
!!! error TS2556: Expected 2 arguments, but got 1 or more.
33-
!!! related TS6210 tests/cases/conformance/expressions/functionCalls/callWithSpread3.ts:1:37: An argument for 'b' was not provided.
34-
takeTwo(...t3); // error on ...t3
35-
~~~~~
43+
!!! related TS6210 tests/cases/conformance/expressions/functionCalls/callWithSpread3.ts:8:33: An argument for 'b' was not provided.
44+
fs2(...s3); // error on ...s3
45+
~~~~~
3646
!!! error TS2554: Expected 2 arguments, but got 3.
47+
fs2_(...s_); // error on ...s_
48+
~~~~~
49+
!!! error TS2557: Expected at least 2 arguments, but got 0 or more.
50+
!!! related TS6210 tests/cases/conformance/expressions/functionCalls/callWithSpread3.ts:9:23: An argument for 'a' was not provided.
51+
fs2_(...s2n_); // error on ...s2n_
52+
~~~~~~~
53+
!!! error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'.
54+
fs2_(...s_, ...s_); // error FIXME: bad error message
55+
~~~~~
56+
!!! error TS2557: Expected at least 2 arguments, but got 1 or more.
57+
!!! related TS6210 tests/cases/conformance/expressions/functionCalls/callWithSpread3.ts:9:34: An argument for 'b' was not provided.
58+
fs2_(...s_, ...s_, ...s_); // error FIXME: worse error message
59+
~~~~~~~~~~~~
60+
!!! error TS2557: Expected at least 2 arguments, but got 2 or more.
61+
// fs2n_(...s2, ...s_); // FIXME: should be a type error
62+
fs2n_(...s2_); // error on ...s2_
63+
~~~~~~
64+
!!! error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.
3765

3866
// ok
39-
takeTwoOrMore(...t4);
40-
takeTwoOrMore(...t4, ...t5);
41-
takeTwoOrMore(...t4, ...t4);
42-
takeTwoOrMore(...t5, ...t4);
67+
fs2_(...s2_);
68+
fs2_(...s2_, ...s_);
69+
fs2_(...s2_, ...s2_);
70+
fs2_(...s_, ...s2_);
71+
fs2n_(...s2n_);
72+
fs2n_(...s2);
73+
// fs2n_(...s2, ...n_); // FIXME: should compile
74+
fs5(...s2, "foo", ...s2);
4375

Lines changed: 51 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,39 @@
11
//// [callWithSpread3.ts]
2-
declare function takeTwo(a: string, b: string): void;
3-
declare const t2: [string, string];
4-
declare const t3: [string, string, string];
5-
declare function takeTwoOrMore (a: string, b: string, ...c: string[]): void
6-
declare const t4: [string, string, ...string[]]
7-
declare const t5: string[]
2+
declare const s2: [string, string];
3+
declare const s3: [string, string, string];
4+
declare const s2_: [string, string, ...string[]];
5+
declare const s_: string[];
6+
declare const n_: number[];
7+
declare const s2n_: [string, string, ...number[]];
8+
9+
declare function fs2(a: string, b: string): void;
10+
declare function fs2_(a: string, b: string, ...c: string[]): void;
11+
declare function fs2n_(a: string, b: string, ...c: number[]): void;
12+
declare function fs5(a: string, b: string, c: string, d: string, e: string): void;
813

914
// error
10-
takeTwo('a', ...t2); // error on ...t2
11-
takeTwo('a', 'b', 'c', ...t2); // error on 'c' and ...t2
12-
takeTwo('a', 'b', ...t2, 'c'); // error on ...t2 and 'c'
13-
takeTwo('a', 'b', 'c', ...t2, 'd'); // error on 'c', ...t2 and 'd'
14-
takeTwo(...t2, 'a'); // error on 'a'
15-
takeTwo(...t3); // error on ...t3
15+
fs2('a', ...s2); // error on ...s2
16+
fs2('a', 'b', 'c', ...s2); // error on 'c' and ...s2
17+
fs2('a', 'b', ...s2, 'c'); // error on ...s2 and 'c'
18+
fs2('a', 'b', 'c', ...s2, 'd'); // error on 'c', ...s2 and 'd'
19+
fs2(...s2, 'a'); // error on 'a'
20+
fs2(...s3); // error on ...s3
21+
fs2_(...s_); // error on ...s_
22+
fs2_(...s2n_); // error on ...s2n_
23+
fs2_(...s_, ...s_); // error FIXME: bad error message
24+
fs2_(...s_, ...s_, ...s_); // error FIXME: worse error message
25+
// fs2n_(...s2, ...s_); // FIXME: should be a type error
26+
fs2n_(...s2_); // error on ...s2_
1627

1728
// ok
18-
takeTwoOrMore(...t4);
19-
takeTwoOrMore(...t4, ...t5);
20-
takeTwoOrMore(...t4, ...t4);
21-
takeTwoOrMore(...t5, ...t4);
29+
fs2_(...s2_);
30+
fs2_(...s2_, ...s_);
31+
fs2_(...s2_, ...s2_);
32+
fs2_(...s_, ...s2_);
33+
fs2n_(...s2n_);
34+
fs2n_(...s2);
35+
// fs2n_(...s2, ...n_); // FIXME: should compile
36+
fs5(...s2, "foo", ...s2);
2237

2338

2439
//// [callWithSpread3.js]
@@ -30,14 +45,24 @@ var __spreadArrays = (this && this.__spreadArrays) || function () {
3045
return r;
3146
};
3247
// error
33-
takeTwo.apply(void 0, __spreadArrays(['a'], t2)); // error on ...t2
34-
takeTwo.apply(void 0, __spreadArrays(['a', 'b', 'c'], t2)); // error on 'c' and ...t2
35-
takeTwo.apply(void 0, __spreadArrays(['a', 'b'], t2, ['c'])); // error on ...t2 and 'c'
36-
takeTwo.apply(void 0, __spreadArrays(['a', 'b', 'c'], t2, ['d'])); // error on 'c', ...t2 and 'd'
37-
takeTwo.apply(void 0, __spreadArrays(t2, ['a'])); // error on 'a'
38-
takeTwo.apply(void 0, t3); // error on ...t3
48+
fs2.apply(void 0, __spreadArrays(['a'], s2)); // error on ...s2
49+
fs2.apply(void 0, __spreadArrays(['a', 'b', 'c'], s2)); // error on 'c' and ...s2
50+
fs2.apply(void 0, __spreadArrays(['a', 'b'], s2, ['c'])); // error on ...s2 and 'c'
51+
fs2.apply(void 0, __spreadArrays(['a', 'b', 'c'], s2, ['d'])); // error on 'c', ...s2 and 'd'
52+
fs2.apply(void 0, __spreadArrays(s2, ['a'])); // error on 'a'
53+
fs2.apply(void 0, s3); // error on ...s3
54+
fs2_.apply(void 0, s_); // error on ...s_
55+
fs2_.apply(void 0, s2n_); // error on ...s2n_
56+
fs2_.apply(void 0, __spreadArrays(s_, s_)); // error FIXME: bad error message
57+
fs2_.apply(void 0, __spreadArrays(s_, s_, s_)); // error FIXME: worse error message
58+
// fs2n_(...s2, ...s_); // FIXME: should be a type error
59+
fs2n_.apply(void 0, s2_); // error on ...s2_
3960
// ok
40-
takeTwoOrMore.apply(void 0, t4);
41-
takeTwoOrMore.apply(void 0, __spreadArrays(t4, t5));
42-
takeTwoOrMore.apply(void 0, __spreadArrays(t4, t4));
43-
takeTwoOrMore.apply(void 0, __spreadArrays(t5, t4));
61+
fs2_.apply(void 0, s2_);
62+
fs2_.apply(void 0, __spreadArrays(s2_, s_));
63+
fs2_.apply(void 0, __spreadArrays(s2_, s2_));
64+
fs2_.apply(void 0, __spreadArrays(s_, s2_));
65+
fs2n_.apply(void 0, s2n_);
66+
fs2n_.apply(void 0, s2);
67+
// fs2n_(...s2, ...n_); // FIXME: should compile
68+
fs5.apply(void 0, __spreadArrays(s2, ["foo"], s2));

0 commit comments

Comments
 (0)