From 2fc2f5c4b975f05e46cf0193b345607ea4983d76 Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Mon, 6 Jun 2016 07:50:32 -0700 Subject: [PATCH] Fix signature help --- src/compiler/checker.ts | 17 +++++---- ...gCommasInFunctionParametersAndArguments.js | 22 ++++++++++++ ...asInFunctionParametersAndArguments.symbols | 26 ++++++++++++++ ...mmasInFunctionParametersAndArguments.types | 35 +++++++++++++++++++ ...gCommasInFunctionParametersAndArguments.ts | 13 +++++++ 5 files changed, 107 insertions(+), 6 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 402d645538..524b9b2f50 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -10321,7 +10321,7 @@ namespace ts { return -1; } - function hasCorrectArity(node: CallLikeExpression, args: Expression[], signature: Signature) { + function hasCorrectArity(node: CallLikeExpression, args: Expression[], signature: Signature, signatureHelpTrailingComma = false) { let argCount: number; // Apparent number of arguments we will have in this call let typeArguments: NodeArray; // Type arguments (undefined if none) let callIsIncomplete: boolean; // In incomplete call we want to be lenient when we have too few arguments @@ -10367,7 +10367,7 @@ namespace ts { return signature.minArgumentCount === 0; } - argCount = args.length; + argCount = signatureHelpTrailingComma ? args.length + 1 : args.length; // If we are missing the close paren, the call is incomplete. callIsIncomplete = (callExpression).arguments.end === callExpression.end; @@ -10968,6 +10968,11 @@ namespace ts { let resultOfFailedInference: InferenceContext; let result: Signature; + // If we are in signature help, a trailing comma indicates that we intend to provide another argument, + // so we will only accept overloads with arity at least 1 higher than the current number of provided arguments. + const signatureHelpTrailingComma = + candidatesOutArray && node.kind === SyntaxKind.CallExpression && (node).arguments.hasTrailingComma; + // Section 4.12.1: // if the candidate list contains one or more signatures for which the type of each argument // expression is a subtype of each corresponding parameter type, the return type of the first @@ -10979,14 +10984,14 @@ namespace ts { // is just important for choosing the best signature. So in the case where there is only one // signature, the subtype pass is useless. So skipping it is an optimization. if (candidates.length > 1) { - result = chooseOverload(candidates, subtypeRelation); + result = chooseOverload(candidates, subtypeRelation, signatureHelpTrailingComma); } if (!result) { // Reinitialize these pointers for round two candidateForArgumentError = undefined; candidateForTypeArgumentError = undefined; resultOfFailedInference = undefined; - result = chooseOverload(candidates, assignableRelation); + result = chooseOverload(candidates, assignableRelation, signatureHelpTrailingComma); } if (result) { return result; @@ -11057,9 +11062,9 @@ namespace ts { diagnostics.add(createDiagnosticForNodeFromMessageChain(node, errorInfo)); } - function chooseOverload(candidates: Signature[], relation: Map) { + function chooseOverload(candidates: Signature[], relation: Map, signatureHelpTrailingComma = false) { for (const originalCandidate of candidates) { - if (!hasCorrectArity(node, args, originalCandidate)) { + if (!hasCorrectArity(node, args, originalCandidate, signatureHelpTrailingComma)) { continue; } diff --git a/tests/baselines/reference/trailingCommasInFunctionParametersAndArguments.js b/tests/baselines/reference/trailingCommasInFunctionParametersAndArguments.js index a9b173f9db..87c925fb22 100644 --- a/tests/baselines/reference/trailingCommasInFunctionParametersAndArguments.js +++ b/tests/baselines/reference/trailingCommasInFunctionParametersAndArguments.js @@ -6,6 +6,19 @@ f1(1,); function f2(...args,) {} f2(...[],); + +// Not confused by overloads +declare function f3(x, ): number; +declare function f3(x, y,): string; + +f3(1,); +f3(1, 2,); + +// Works for constructors too +class X { + constructor(a,) { } +} +new X(1,); //// [trailingCommasInFunctionParametersAndArguments.js] @@ -18,3 +31,12 @@ function f2() { } } f2.apply(void 0, []); +f3(1); +f3(1, 2); +// Works for constructors too +var X = (function () { + function X(a) { + } + return X; +}()); +new X(1); diff --git a/tests/baselines/reference/trailingCommasInFunctionParametersAndArguments.symbols b/tests/baselines/reference/trailingCommasInFunctionParametersAndArguments.symbols index dd9ce5319c..b146d230ba 100644 --- a/tests/baselines/reference/trailingCommasInFunctionParametersAndArguments.symbols +++ b/tests/baselines/reference/trailingCommasInFunctionParametersAndArguments.symbols @@ -13,3 +13,29 @@ function f2(...args,) {} f2(...[],); >f2 : Symbol(f2, Decl(trailingCommasInFunctionParametersAndArguments.ts, 2, 7)) +// Not confused by overloads +declare function f3(x, ): number; +>f3 : Symbol(f3, Decl(trailingCommasInFunctionParametersAndArguments.ts, 6, 11), Decl(trailingCommasInFunctionParametersAndArguments.ts, 9, 33)) +>x : Symbol(x, Decl(trailingCommasInFunctionParametersAndArguments.ts, 9, 20)) + +declare function f3(x, y,): string; +>f3 : Symbol(f3, Decl(trailingCommasInFunctionParametersAndArguments.ts, 6, 11), Decl(trailingCommasInFunctionParametersAndArguments.ts, 9, 33)) +>x : Symbol(x, Decl(trailingCommasInFunctionParametersAndArguments.ts, 10, 20)) +>y : Symbol(y, Decl(trailingCommasInFunctionParametersAndArguments.ts, 10, 22)) + +f3(1,); +>f3 : Symbol(f3, Decl(trailingCommasInFunctionParametersAndArguments.ts, 6, 11), Decl(trailingCommasInFunctionParametersAndArguments.ts, 9, 33)) + +f3(1, 2,); +>f3 : Symbol(f3, Decl(trailingCommasInFunctionParametersAndArguments.ts, 6, 11), Decl(trailingCommasInFunctionParametersAndArguments.ts, 9, 33)) + +// Works for constructors too +class X { +>X : Symbol(X, Decl(trailingCommasInFunctionParametersAndArguments.ts, 13, 18)) + + constructor(a,) { } +>a : Symbol(a, Decl(trailingCommasInFunctionParametersAndArguments.ts, 17, 16)) +} +new X(1,); +>X : Symbol(X, Decl(trailingCommasInFunctionParametersAndArguments.ts, 13, 18)) + diff --git a/tests/baselines/reference/trailingCommasInFunctionParametersAndArguments.types b/tests/baselines/reference/trailingCommasInFunctionParametersAndArguments.types index 0a8d34d1df..36de78fc8b 100644 --- a/tests/baselines/reference/trailingCommasInFunctionParametersAndArguments.types +++ b/tests/baselines/reference/trailingCommasInFunctionParametersAndArguments.types @@ -18,3 +18,38 @@ f2(...[],); >...[] : undefined >[] : undefined[] +// Not confused by overloads +declare function f3(x, ): number; +>f3 : { (x: any): number; (x: any, y: any): string; } +>x : any + +declare function f3(x, y,): string; +>f3 : { (x: any): number; (x: any, y: any): string; } +>x : any +>y : any + +f3(1,); +>f3(1,) : number +>f3(1,) : number +>f3 : { (x: any): number; (x: any, y: any): string; } +>1 : number + +f3(1, 2,); +>f3(1, 2,) : string +>f3(1, 2,) : string +>f3 : { (x: any): number; (x: any, y: any): string; } +>1 : number +>2 : number + +// Works for constructors too +class X { +>X : X + + constructor(a,) { } +>a : any +} +new X(1,); +>new X(1,) : X +>X : typeof X +>1 : number + diff --git a/tests/cases/conformance/es7/trailingCommasInFunctionParametersAndArguments.ts b/tests/cases/conformance/es7/trailingCommasInFunctionParametersAndArguments.ts index 4b628e7e55..9c21d7f24e 100644 --- a/tests/cases/conformance/es7/trailingCommasInFunctionParametersAndArguments.ts +++ b/tests/cases/conformance/es7/trailingCommasInFunctionParametersAndArguments.ts @@ -5,3 +5,16 @@ f1(1,); function f2(...args,) {} f2(...[],); + +// Not confused by overloads +declare function f3(x, ): number; +declare function f3(x, y,): string; + +f3(1,); +f3(1, 2,); + +// Works for constructors too +class X { + constructor(a,) { } +} +new X(1,);