@@ -18200,7 +18200,6 @@ namespace ts {
18200
18200
18201
18201
function hasCorrectArity(node: CallLikeExpression, args: ReadonlyArray<Expression>, signature: Signature, signatureHelpTrailingComma = false) {
18202
18202
let argCount: number; // Apparent number of arguments we will have in this call
18203
- let typeArguments: NodeArray<TypeNode> | undefined; // Type arguments (undefined if none)
18204
18203
let callIsIncomplete = false; // In incomplete call we want to be lenient when we have too few arguments
18205
18204
let spreadArgIndex = -1;
18206
18205
@@ -18213,7 +18212,6 @@ namespace ts {
18213
18212
// Even if the call is incomplete, we'll have a missing expression as our last argument,
18214
18213
// so we can say the count is just the arg list length
18215
18214
argCount = args.length;
18216
- typeArguments = node.typeArguments;
18217
18215
18218
18216
if (node.template.kind === SyntaxKind.TemplateExpression) {
18219
18217
// If a tagged template expression lacks a tail literal, the call is incomplete.
@@ -18231,7 +18229,6 @@ namespace ts {
18231
18229
}
18232
18230
}
18233
18231
else if (node.kind === SyntaxKind.Decorator) {
18234
- typeArguments = undefined;
18235
18232
argCount = getEffectiveArgumentCount(node, /*args*/ undefined!, signature);
18236
18233
}
18237
18234
else {
@@ -18246,14 +18243,9 @@ namespace ts {
18246
18243
// If we are missing the close parenthesis, the call is incomplete.
18247
18244
callIsIncomplete = node.arguments.end === node.end;
18248
18245
18249
- typeArguments = node.typeArguments;
18250
18246
spreadArgIndex = getSpreadArgumentIndex(args);
18251
18247
}
18252
18248
18253
- if (!hasCorrectTypeArgumentArity(signature, typeArguments)) {
18254
- return false;
18255
- }
18256
-
18257
18249
// If a spread argument is present, check that it corresponds to a rest parameter or at least that it's in the valid range.
18258
18250
if (spreadArgIndex >= 0) {
18259
18251
return spreadArgIndex >= getMinArgumentCount(signature) && (hasEffectiveRestParameter(signature) || spreadArgIndex < getParameterCount(signature));
@@ -18903,6 +18895,29 @@ namespace ts {
18903
18895
}
18904
18896
}
18905
18897
18898
+ function getArgumentArityError(node: Node, signatures: ReadonlyArray<Signature>, args: ReadonlyArray<Expression>) {
18899
+ let min = Number.POSITIVE_INFINITY;
18900
+ let max = Number.NEGATIVE_INFINITY;
18901
+ for (const sig of signatures) {
18902
+ min = Math.min(min, getMinArgumentCount(sig));
18903
+ max = Math.max(max, getParameterCount(sig));
18904
+ }
18905
+ const hasRestParameter = some(signatures, hasEffectiveRestParameter);
18906
+ const hasSpreadArgument = getSpreadArgumentIndex(args) > -1;
18907
+ const paramCount = hasRestParameter ? min :
18908
+ min < max ? min + "-" + max :
18909
+ min;
18910
+ let argCount = args.length;
18911
+ if (argCount <= max && hasSpreadArgument) {
18912
+ argCount--;
18913
+ }
18914
+ const error = hasRestParameter && hasSpreadArgument ? Diagnostics.Expected_at_least_0_arguments_but_got_1_or_more :
18915
+ hasRestParameter ? Diagnostics.Expected_at_least_0_arguments_but_got_1 :
18916
+ hasSpreadArgument ? Diagnostics.Expected_0_arguments_but_got_1_or_more :
18917
+ Diagnostics.Expected_0_arguments_but_got_1;
18918
+ return createDiagnosticForNode(node, error, paramCount, argCount);
18919
+ }
18920
+
18906
18921
function getTypeArgumentArityError(node: Node, signatures: ReadonlyArray<Signature>, typeArguments: NodeArray<TypeNode>) {
18907
18922
let min = Infinity;
18908
18923
let max = -Infinity;
@@ -18993,6 +19008,7 @@ namespace ts {
18993
19008
// foo<number>(0);
18994
19009
//
18995
19010
let candidateForArgumentError: Signature | undefined;
19011
+ let candidateForArgumentArityError: Signature | undefined;
18996
19012
let candidateForTypeArgumentError: Signature | undefined;
18997
19013
let result: Signature | undefined;
18998
19014
@@ -19037,33 +19053,17 @@ namespace ts {
19037
19053
// an error, we don't need to exclude any arguments, although it would cause no harm to do so.
19038
19054
checkApplicableSignature(node, args!, candidateForArgumentError, assignableRelation, /*excludeArgument*/ undefined, /*reportErrors*/ true);
19039
19055
}
19056
+ else if (candidateForArgumentArityError) {
19057
+ diagnostics.add(getArgumentArityError(node, [candidateForArgumentArityError], args!));
19058
+ }
19040
19059
else if (candidateForTypeArgumentError) {
19041
19060
checkTypeArguments(candidateForTypeArgumentError, (node as CallExpression | TaggedTemplateExpression).typeArguments!, /*reportErrors*/ true, fallbackError);
19042
19061
}
19043
19062
else if (typeArguments && every(signatures, sig => length(sig.typeParameters) !== typeArguments!.length)) {
19044
19063
diagnostics.add(getTypeArgumentArityError(node, signatures, typeArguments));
19045
19064
}
19046
19065
else if (args) {
19047
- let min = Number.POSITIVE_INFINITY;
19048
- let max = Number.NEGATIVE_INFINITY;
19049
- for (const sig of signatures) {
19050
- min = Math.min(min, getMinArgumentCount(sig));
19051
- max = Math.max(max, getParameterCount(sig));
19052
- }
19053
- const hasRestParameter = some(signatures, hasEffectiveRestParameter);
19054
- const hasSpreadArgument = getSpreadArgumentIndex(args) > -1;
19055
- const paramCount = hasRestParameter ? min :
19056
- min < max ? min + "-" + max :
19057
- min;
19058
- let argCount = args.length;
19059
- if (argCount <= max && hasSpreadArgument) {
19060
- argCount--;
19061
- }
19062
- const error = hasRestParameter && hasSpreadArgument ? Diagnostics.Expected_at_least_0_arguments_but_got_1_or_more :
19063
- hasRestParameter ? Diagnostics.Expected_at_least_0_arguments_but_got_1 :
19064
- hasSpreadArgument ? Diagnostics.Expected_0_arguments_but_got_1_or_more :
19065
- Diagnostics.Expected_0_arguments_but_got_1;
19066
- diagnostics.add(createDiagnosticForNode(node, error, paramCount, argCount));
19066
+ diagnostics.add(getArgumentArityError(node, signatures, args));
19067
19067
}
19068
19068
else if (fallbackError) {
19069
19069
diagnostics.add(createDiagnosticForNode(node, fallbackError));
@@ -19104,11 +19104,12 @@ namespace ts {
19104
19104
19105
19105
function chooseOverload(candidates: Signature[], relation: Map<RelationComparisonResult>, signatureHelpTrailingComma = false) {
19106
19106
candidateForArgumentError = undefined;
19107
+ candidateForArgumentArityError = undefined;
19107
19108
candidateForTypeArgumentError = undefined;
19108
19109
19109
19110
if (isSingleNonGenericCandidate) {
19110
19111
const candidate = candidates[0];
19111
- if (!hasCorrectArity(node, args!, candidate, signatureHelpTrailingComma)) {
19112
+ if (typeArguments || !hasCorrectArity(node, args!, candidate, signatureHelpTrailingComma)) {
19112
19113
return undefined;
19113
19114
}
19114
19115
if (!checkApplicableSignature(node, args!, candidate, relation, excludeArgument, /*reportErrors*/ false)) {
@@ -19120,7 +19121,7 @@ namespace ts {
19120
19121
19121
19122
for (let candidateIndex = 0; candidateIndex < candidates.length; candidateIndex++) {
19122
19123
const originalCandidate = candidates[candidateIndex];
19123
- if (!hasCorrectArity(node, args!, originalCandidate, signatureHelpTrailingComma)) {
19124
+ if (!hasCorrectTypeArgumentArity(originalCandidate, typeArguments) || ! hasCorrectArity(node, args!, originalCandidate, signatureHelpTrailingComma)) {
19124
19125
continue;
19125
19126
}
19126
19127
@@ -19148,6 +19149,12 @@ namespace ts {
19148
19149
}
19149
19150
const isJavascript = isInJavaScriptFile(candidate.declaration);
19150
19151
candidate = getSignatureInstantiation(candidate, typeArgumentTypes, isJavascript);
19152
+ // If the original signature has a rest type parameter, instantiation may produce a
19153
+ // signature with different arity and we need to perform another arity check.
19154
+ if (getRestTypeParameter(originalCandidate) && !hasCorrectArity(node, args!, candidate, signatureHelpTrailingComma)) {
19155
+ candidateForArgumentArityError = candidate;
19156
+ break;
19157
+ }
19151
19158
}
19152
19159
if (!checkApplicableSignature(node, args!, candidate, relation, excludeArgument, /*reportErrors*/ false)) {
19153
19160
candidateForArgumentError = candidate;
0 commit comments