Skip to content

Commit 261386d

Browse files
rchaser53elibarzilay
authored andcommitted
fix error when use spread arguments twice
1 parent 4ee013d commit 261386d

File tree

6 files changed

+142
-14
lines changed

6 files changed

+142
-14
lines changed

src/compiler/checker.ts

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25063,10 +25063,18 @@ namespace ts {
2506325063
// If we are missing the close parenthesis, the call is incomplete.
2506425064
callIsIncomplete = node.arguments.end === node.end;
2506525065

25066-
// If a spread argument is present, check that it corresponds to a rest parameter or at least that it's in the valid range.
25067-
const spreadArgIndex = getSpreadArgumentIndex(args);
25068-
if (spreadArgIndex >= 0) {
25069-
return spreadArgIndex >= getMinArgumentCount(signature) && (hasEffectiveRestParameter(signature) || spreadArgIndex < getParameterCount(signature));
25066+
// If one or more spread arguments are present, check that they correspond to a rest parameter or at least that they are in the valid range.
25067+
const firstSpreadArgIndex = getSpreadArgumentIndex(args);
25068+
if (firstSpreadArgIndex >= 0) {
25069+
if (firstSpreadArgIndex === args.length - 1) {
25070+
return firstSpreadArgIndex >= getMinArgumentCount(signature) && (hasEffectiveRestParameter(signature) || firstSpreadArgIndex < getParameterCount(signature));
25071+
}
25072+
25073+
let totalCount = countSpreadArgumentLength(<SpreadElement>args[firstSpreadArgIndex]);
25074+
for (let i = firstSpreadArgIndex; i < args.length; i++) {
25075+
totalCount += isSpreadArgument(args[i]) ? countSpreadArgumentLength(<SpreadElement>args[i]) : 1;
25076+
}
25077+
return totalCount >= getMinArgumentCount(signature) && (hasEffectiveRestParameter(signature) || totalCount < getParameterCount(signature));
2507025078
}
2507125079
}
2507225080

@@ -25089,6 +25097,11 @@ namespace ts {
2508925097
return true;
2509025098
}
2509125099

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+
2509225105
function hasCorrectTypeArgumentArity(signature: Signature, typeArguments: NodeArray<TypeNode> | undefined) {
2509325106
// If the user supplied type arguments, but the number of type arguments does not match
2509425107
// the declared number of type parameters, the call has an incorrect arity.
@@ -25544,7 +25557,7 @@ namespace ts {
2554425557
const spreadArgument = <SpreadElement>args[length - 1];
2554525558
const type = flowLoopCount ? checkExpression(spreadArgument.expression) : checkExpressionCached(spreadArgument.expression);
2554625559
if (isTupleType(type)) {
25547-
const typeArguments = getTypeArguments(<TypeReference>type);
25560+
const typeArguments = getTypeArguments(type);
2554825561
const restIndex = type.target.hasRestElement ? typeArguments.length - 1 : -1;
2554925562
const syntheticArgs = map(typeArguments, (t, i) => createSyntheticExpression(spreadArgument, t, /*isSpread*/ i === restIndex, type.target.labeledElementDeclarations?.[i]));
2555025563
return concatenate(args.slice(0, length - 1), syntheticArgs);

tests/baselines/reference/callWithSpread3.errors.txt

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
1-
tests/cases/conformance/expressions/functionCalls/callWithSpread3.ts(5,14): error TS2554: Expected 2 arguments, but got 3.
2-
tests/cases/conformance/expressions/functionCalls/callWithSpread3.ts(6,19): error TS2554: Expected 2 arguments, but got 5.
3-
tests/cases/conformance/expressions/functionCalls/callWithSpread3.ts(7,19): error TS2556: Expected 2 arguments, but got 4 or more.
4-
tests/cases/conformance/expressions/functionCalls/callWithSpread3.ts(8,19): error TS2556: Expected 2 arguments, but got 5 or more.
5-
tests/cases/conformance/expressions/functionCalls/callWithSpread3.ts(9,16): error TS2556: Expected 2 arguments, but got 1 or more.
6-
tests/cases/conformance/expressions/functionCalls/callWithSpread3.ts(10,9): error TS2554: Expected 2 arguments, but got 3.
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.
77

88

99
==== tests/cases/conformance/expressions/functionCalls/callWithSpread3.ts (6 errors) ====
1010
declare function takeTwo(a: string, b: string): void;
1111
declare const t2: [string, string];
1212
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[]
1316

17+
// error
1418
takeTwo('a', ...t2); // error on ...t2
1519
~~~~~
1620
!!! error TS2554: Expected 2 arguments, but got 3.
@@ -29,4 +33,11 @@ tests/cases/conformance/expressions/functionCalls/callWithSpread3.ts(10,9): erro
2933
!!! related TS6210 tests/cases/conformance/expressions/functionCalls/callWithSpread3.ts:1:37: An argument for 'b' was not provided.
3034
takeTwo(...t3); // error on ...t3
3135
~~~~~
32-
!!! error TS2554: Expected 2 arguments, but got 3.
36+
!!! error TS2554: Expected 2 arguments, but got 3.
37+
38+
// ok
39+
takeTwoOrMore(...t4);
40+
takeTwoOrMore(...t4, ...t5);
41+
takeTwoOrMore(...t4, ...t4);
42+
takeTwoOrMore(...t5, ...t4);
43+

tests/baselines/reference/callWithSpread3.js

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,24 @@
22
declare function takeTwo(a: string, b: string): void;
33
declare const t2: [string, string];
44
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[]
58

9+
// error
610
takeTwo('a', ...t2); // error on ...t2
711
takeTwo('a', 'b', 'c', ...t2); // error on 'c' and ...t2
812
takeTwo('a', 'b', ...t2, 'c'); // error on ...t2 and 'c'
913
takeTwo('a', 'b', 'c', ...t2, 'd'); // error on 'c', ...t2 and 'd'
1014
takeTwo(...t2, 'a'); // error on 'a'
11-
takeTwo(...t3); // error on ...t3
15+
takeTwo(...t3); // error on ...t3
16+
17+
// ok
18+
takeTwoOrMore(...t4);
19+
takeTwoOrMore(...t4, ...t5);
20+
takeTwoOrMore(...t4, ...t4);
21+
takeTwoOrMore(...t5, ...t4);
22+
1223

1324
//// [callWithSpread3.js]
1425
var __spreadArrays = (this && this.__spreadArrays) || function () {
@@ -18,9 +29,15 @@ var __spreadArrays = (this && this.__spreadArrays) || function () {
1829
r[k] = a[j];
1930
return r;
2031
};
32+
// error
2133
takeTwo.apply(void 0, __spreadArrays(['a'], t2)); // error on ...t2
2234
takeTwo.apply(void 0, __spreadArrays(['a', 'b', 'c'], t2)); // error on 'c' and ...t2
2335
takeTwo.apply(void 0, __spreadArrays(['a', 'b'], t2, ['c'])); // error on ...t2 and 'c'
2436
takeTwo.apply(void 0, __spreadArrays(['a', 'b', 'c'], t2, ['d'])); // error on 'c', ...t2 and 'd'
2537
takeTwo.apply(void 0, __spreadArrays(t2, ['a'])); // error on 'a'
2638
takeTwo.apply(void 0, t3); // error on ...t3
39+
// 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));

tests/baselines/reference/callWithSpread3.symbols

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,19 @@ declare const t2: [string, string];
1010
declare const t3: [string, string, string];
1111
>t3 : Symbol(t3, Decl(callWithSpread3.ts, 2, 13))
1212

13+
declare function takeTwoOrMore (a: string, b: string, ...c: string[]): void
14+
>takeTwoOrMore : Symbol(takeTwoOrMore, Decl(callWithSpread3.ts, 2, 43))
15+
>a : Symbol(a, Decl(callWithSpread3.ts, 3, 32))
16+
>b : Symbol(b, Decl(callWithSpread3.ts, 3, 42))
17+
>c : Symbol(c, Decl(callWithSpread3.ts, 3, 53))
18+
19+
declare const t4: [string, string, ...string[]]
20+
>t4 : Symbol(t4, Decl(callWithSpread3.ts, 4, 13))
21+
22+
declare const t5: string[]
23+
>t5 : Symbol(t5, Decl(callWithSpread3.ts, 5, 13))
24+
25+
// error
1326
takeTwo('a', ...t2); // error on ...t2
1427
>takeTwo : Symbol(takeTwo, Decl(callWithSpread3.ts, 0, 0))
1528
>t2 : Symbol(t2, Decl(callWithSpread3.ts, 1, 13))
@@ -34,3 +47,23 @@ takeTwo(...t3); // error on ...t3
3447
>takeTwo : Symbol(takeTwo, Decl(callWithSpread3.ts, 0, 0))
3548
>t3 : Symbol(t3, Decl(callWithSpread3.ts, 2, 13))
3649

50+
// ok
51+
takeTwoOrMore(...t4);
52+
>takeTwoOrMore : Symbol(takeTwoOrMore, Decl(callWithSpread3.ts, 2, 43))
53+
>t4 : Symbol(t4, Decl(callWithSpread3.ts, 4, 13))
54+
55+
takeTwoOrMore(...t4, ...t5);
56+
>takeTwoOrMore : Symbol(takeTwoOrMore, Decl(callWithSpread3.ts, 2, 43))
57+
>t4 : Symbol(t4, Decl(callWithSpread3.ts, 4, 13))
58+
>t5 : Symbol(t5, Decl(callWithSpread3.ts, 5, 13))
59+
60+
takeTwoOrMore(...t4, ...t4);
61+
>takeTwoOrMore : Symbol(takeTwoOrMore, Decl(callWithSpread3.ts, 2, 43))
62+
>t4 : Symbol(t4, Decl(callWithSpread3.ts, 4, 13))
63+
>t4 : Symbol(t4, Decl(callWithSpread3.ts, 4, 13))
64+
65+
takeTwoOrMore(...t5, ...t4);
66+
>takeTwoOrMore : Symbol(takeTwoOrMore, Decl(callWithSpread3.ts, 2, 43))
67+
>t5 : Symbol(t5, Decl(callWithSpread3.ts, 5, 13))
68+
>t4 : Symbol(t4, Decl(callWithSpread3.ts, 4, 13))
69+

tests/baselines/reference/callWithSpread3.types

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,19 @@ declare const t2: [string, string];
1010
declare const t3: [string, string, string];
1111
>t3 : [string, string, string]
1212

13+
declare function takeTwoOrMore (a: string, b: string, ...c: string[]): void
14+
>takeTwoOrMore : (a: string, b: string, ...c: string[]) => void
15+
>a : string
16+
>b : string
17+
>c : string[]
18+
19+
declare const t4: [string, string, ...string[]]
20+
>t4 : [string, string, ...string[]]
21+
22+
declare const t5: string[]
23+
>t5 : string[]
24+
25+
// error
1326
takeTwo('a', ...t2); // error on ...t2
1427
>takeTwo('a', ...t2) : void
1528
>takeTwo : (a: string, b: string) => void
@@ -58,3 +71,34 @@ takeTwo(...t3); // error on ...t3
5871
>...t3 : string
5972
>t3 : [string, string, string]
6073

74+
// ok
75+
takeTwoOrMore(...t4);
76+
>takeTwoOrMore(...t4) : void
77+
>takeTwoOrMore : (a: string, b: string, ...c: string[]) => void
78+
>...t4 : string
79+
>t4 : [string, string, ...string[]]
80+
81+
takeTwoOrMore(...t4, ...t5);
82+
>takeTwoOrMore(...t4, ...t5) : void
83+
>takeTwoOrMore : (a: string, b: string, ...c: string[]) => void
84+
>...t4 : string
85+
>t4 : [string, string, ...string[]]
86+
>...t5 : string
87+
>t5 : string[]
88+
89+
takeTwoOrMore(...t4, ...t4);
90+
>takeTwoOrMore(...t4, ...t4) : void
91+
>takeTwoOrMore : (a: string, b: string, ...c: string[]) => void
92+
>...t4 : string
93+
>t4 : [string, string, ...string[]]
94+
>...t4 : string
95+
>t4 : [string, string, ...string[]]
96+
97+
takeTwoOrMore(...t5, ...t4);
98+
>takeTwoOrMore(...t5, ...t4) : void
99+
>takeTwoOrMore : (a: string, b: string, ...c: string[]) => void
100+
>...t5 : string
101+
>t5 : string[]
102+
>...t4 : string
103+
>t4 : [string, string, ...string[]]
104+
Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,20 @@
11
declare function takeTwo(a: string, b: string): void;
22
declare const t2: [string, string];
33
declare const t3: [string, string, string];
4+
declare function takeTwoOrMore (a: string, b: string, ...c: string[]): void
5+
declare const t4: [string, string, ...string[]]
6+
declare const t5: string[]
47

8+
// error
59
takeTwo('a', ...t2); // error on ...t2
610
takeTwo('a', 'b', 'c', ...t2); // error on 'c' and ...t2
711
takeTwo('a', 'b', ...t2, 'c'); // error on ...t2 and 'c'
812
takeTwo('a', 'b', 'c', ...t2, 'd'); // error on 'c', ...t2 and 'd'
913
takeTwo(...t2, 'a'); // error on 'a'
10-
takeTwo(...t3); // error on ...t3
14+
takeTwo(...t3); // error on ...t3
15+
16+
// ok
17+
takeTwoOrMore(...t4);
18+
takeTwoOrMore(...t4, ...t5);
19+
takeTwoOrMore(...t4, ...t4);
20+
takeTwoOrMore(...t5, ...t4);

0 commit comments

Comments
 (0)