From ab3326f7b7b0631e2cb82f11d7b59035fc4d5d49 Mon Sep 17 00:00:00 2001 From: Jason Freeman Date: Fri, 26 Sep 2014 13:51:13 -0700 Subject: [PATCH] Fix arity checking for partial overload resolution --- src/compiler/checker.ts | 43 +++++++++++-------- ...trailingSeparatorInFunctionCall.errors.txt | 10 ++++- .../fourslash/signatureHelpOnOverloads.ts | 6 +-- .../signatureHelpOnOverloadsDifferentArity.ts | 20 +++++++++ 4 files changed, 56 insertions(+), 23 deletions(-) create mode 100644 tests/cases/fourslash/signatureHelpOnOverloadsDifferentArity.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 99b387dd18c..fa8b516924b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4331,25 +4331,32 @@ module ts { } function signatureHasCorrectArity(node: CallExpression, signature: Signature): boolean { - var args = node.arguments || emptyArray; - var isCorrect = args.length >= signature.minArgumentCount && - (signature.hasRestParameter || args.length <= signature.parameters.length) && - (!node.typeArguments || signature.typeParameters && node.typeArguments.length === signature.typeParameters.length); - - // For error recovery, since we have parsed OmittedExpressions for any extra commas - // in the argument list, if we see any OmittedExpressions, just return true. - // The reason this is ok is because omitted expressions here are syntactically - // illegal, and will cause a parse error. - // Note: It may be worth keeping the upper bound check on arity, but removing - // the lower bound check if there are omitted expressions. - if (!isCorrect) { - // Technically this type assertion is not safe because args could be initialized to emptyArray - // above. - if ((>args).hasTrailingComma || forEach(args, arg => arg.kind === SyntaxKind.OmittedExpression)) { - return true; - } + if (!node.arguments) { + // This only happens when we have something of the form: + // new C + // + return signature.minArgumentCount === 0; } - return isCorrect; + + // For IDE scenarios, since we may have an incomplete call, we make two modifications + // to arity checking. + // 1. A trailing comma is tantamount to adding another argument + // 2. If the call is incomplete (no closing paren) allow fewer arguments than expected + var args = node.arguments; + var numberOfArgs = args.hasTrailingComma ? args.length + 1 : args.length; + var hasTooManyArguments = !signature.hasRestParameter && numberOfArgs > signature.parameters.length; + var hasRightNumberOfTypeArguments = !node.typeArguments || + (signature.typeParameters && node.typeArguments.length === signature.typeParameters.length); + + if (hasTooManyArguments || !hasRightNumberOfTypeArguments) { + return false; + } + + // If we are missing the close paren, the call is incomplete, and we should skip + // the lower bound check. + var callIsIncomplete = args.end === node.end; + var hasEnoughArguments = numberOfArgs >= signature.minArgumentCount; + return callIsIncomplete || hasEnoughArguments; } // If type has a single call signature and no other members, return that signature. Otherwise, return undefined. diff --git a/tests/baselines/reference/trailingSeparatorInFunctionCall.errors.txt b/tests/baselines/reference/trailingSeparatorInFunctionCall.errors.txt index 3edeb834baa..986f2dedf6e 100644 --- a/tests/baselines/reference/trailingSeparatorInFunctionCall.errors.txt +++ b/tests/baselines/reference/trailingSeparatorInFunctionCall.errors.txt @@ -1,18 +1,24 @@ tests/cases/compiler/trailingSeparatorInFunctionCall.ts(4,7): error TS1009: Trailing comma not allowed. tests/cases/compiler/trailingSeparatorInFunctionCall.ts(9,8): error TS1009: Trailing comma not allowed. +tests/cases/compiler/trailingSeparatorInFunctionCall.ts(4,1): error TS2346: Supplied parameters do not match any signature of call target. +tests/cases/compiler/trailingSeparatorInFunctionCall.ts(9,1): error TS2346: Supplied parameters do not match any signature of call target. -==== tests/cases/compiler/trailingSeparatorInFunctionCall.ts (2 errors) ==== +==== tests/cases/compiler/trailingSeparatorInFunctionCall.ts (4 errors) ==== function f(x, y) { } f(1, 2, ); ~ !!! error TS1009: Trailing comma not allowed. + ~~~~~~~~~ +!!! error TS2346: Supplied parameters do not match any signature of call target. function f2(x: T, y: T) { } f2(1, 2, ); ~ -!!! error TS1009: Trailing comma not allowed. \ No newline at end of file +!!! error TS1009: Trailing comma not allowed. + ~~~~~~~~~~ +!!! error TS2346: Supplied parameters do not match any signature of call target. \ No newline at end of file diff --git a/tests/cases/fourslash/signatureHelpOnOverloads.ts b/tests/cases/fourslash/signatureHelpOnOverloads.ts index 83d7b75a4cf..9712c9dc301 100644 --- a/tests/cases/fourslash/signatureHelpOnOverloads.ts +++ b/tests/cases/fourslash/signatureHelpOnOverloads.ts @@ -13,6 +13,6 @@ verify.currentParameterSpanIs("x: string"); edit.insert("'',"); verify.signatureHelpCountIs(2); -// verify.currentSignatureHelpIs("fn(x: string, y: number): any"); -// verify.currentParameterHelpArgumentNameIs("y"); -// verify.currentParameterSpanIs("y: number"); +verify.currentSignatureHelpIs("fn(x: string, y: number): any"); +verify.currentParameterHelpArgumentNameIs("y"); +verify.currentParameterSpanIs("y: number"); diff --git a/tests/cases/fourslash/signatureHelpOnOverloadsDifferentArity.ts b/tests/cases/fourslash/signatureHelpOnOverloadsDifferentArity.ts new file mode 100644 index 00000000000..fe18f655ed4 --- /dev/null +++ b/tests/cases/fourslash/signatureHelpOnOverloadsDifferentArity.ts @@ -0,0 +1,20 @@ +/// + +////declare function f(s: string); +////declare function f(n: number); +////declare function f(s: string, b: boolean); +////declare function f(n: number, b: boolean); +//// +////f(1/**/ + +goTo.marker(); +verify.signatureHelpCountIs(4); +verify.currentSignatureHelpIs("f(n: number): any"); +verify.currentParameterHelpArgumentNameIs("n"); +verify.currentParameterSpanIs("n: number"); + +edit.insert(", "); +verify.signatureHelpCountIs(4); +verify.currentSignatureHelpIs("f(n: number, b: boolean): any"); +verify.currentParameterHelpArgumentNameIs("b"); +verify.currentParameterSpanIs("b: boolean"); \ No newline at end of file