Fix signature help

This commit is contained in:
Andy Hanson 2016-06-06 07:50:32 -07:00
parent 8b0974a77e
commit 2fc2f5c4b9
5 changed files with 107 additions and 6 deletions

View file

@ -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<TypeNode>; // 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>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 && (<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<RelationComparisonResult>) {
function chooseOverload(candidates: Signature[], relation: Map<RelationComparisonResult>, signatureHelpTrailingComma = false) {
for (const originalCandidate of candidates) {
if (!hasCorrectArity(node, args, originalCandidate)) {
if (!hasCorrectArity(node, args, originalCandidate, signatureHelpTrailingComma)) {
continue;
}

View file

@ -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;
<number>f3(1,);
<string>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);

View file

@ -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))
<number>f3(1,);
>f3 : Symbol(f3, Decl(trailingCommasInFunctionParametersAndArguments.ts, 6, 11), Decl(trailingCommasInFunctionParametersAndArguments.ts, 9, 33))
<string>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))

View file

@ -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
<number>f3(1,);
><number>f3(1,) : number
>f3(1,) : number
>f3 : { (x: any): number; (x: any, y: any): string; }
>1 : number
<string>f3(1, 2,);
><string>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

View file

@ -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;
<number>f3(1,);
<string>f3(1, 2,);
// Works for constructors too
class X {
constructor(a,) { }
}
new X(1,);