@@ -75,6 +75,9 @@ namespace ts {
7575 undefinedSymbol.declarations = [];
7676 const argumentsSymbol = createSymbol(SymbolFlags.Property, "arguments");
7777
78+ /** This will be set during calls to `getResolvedSignature` where services determines an apparent number of arguments greater than what is actually provided. */
79+ let apparentArgumentCount: number | undefined;
80+
7881 // for public members that accept a Node or one of its subtypes, we must guard against
7982 // synthetic nodes created during transformations by calling `getParseTreeNode`.
8083 // for most of these, we perform the guard only on `checker` to avoid any possible
@@ -160,9 +163,12 @@ namespace ts {
160163 return node ? getContextualType(node) : undefined;
161164 },
162165 getFullyQualifiedName,
163- getResolvedSignature: (node, candidatesOutArray? ) => {
166+ getResolvedSignature: (node, candidatesOutArray, theArgumentCount ) => {
164167 node = getParseTreeNode(node, isCallLikeExpression);
165- return node ? getResolvedSignature(node, candidatesOutArray) : undefined;
168+ apparentArgumentCount = theArgumentCount;
169+ const res = node ? getResolvedSignature(node, candidatesOutArray) : undefined;
170+ apparentArgumentCount = undefined;
171+ return res;
166172 },
167173 getConstantValue: node => {
168174 node = getParseTreeNode(node, canHaveConstantValue);
@@ -6313,12 +6319,12 @@ namespace ts {
63136319 // If a type parameter does not have a default type, or if the default type
63146320 // is a forward reference, the empty object type is used.
63156321 for (let i = numTypeArguments; i < numTypeParameters; i++) {
6316- typeArguments[i] = isJavaScript ? anyType : emptyObjectType ;
6322+ typeArguments[i] = getDefaultTypeArgumentType( isJavaScript) ;
63176323 }
63186324 for (let i = numTypeArguments; i < numTypeParameters; i++) {
63196325 const mapper = createTypeMapper(typeParameters, typeArguments);
63206326 const defaultType = getDefaultFromTypeParameter(typeParameters[i]);
6321- typeArguments[i] = defaultType ? instantiateType(defaultType, mapper) : isJavaScript ? anyType : emptyObjectType ;
6327+ typeArguments[i] = defaultType ? instantiateType(defaultType, mapper) : getDefaultTypeArgumentType( isJavaScript) ;
63226328 }
63236329 }
63246330 }
@@ -7968,15 +7974,16 @@ namespace ts {
79687974 };
79697975 }
79707976
7971- function createTypeMapper(sources: Type[], targets: Type[]): TypeMapper {
7977+ function createTypeMapper(sources: TypeParameter[], targets: Type[]): TypeMapper {
7978+ Debug.assert(targets === undefined || sources.length === targets.length);
79727979 const mapper: TypeMapper = sources.length === 1 ? makeUnaryTypeMapper(sources[0], targets ? targets[0] : anyType) :
79737980 sources.length === 2 ? makeBinaryTypeMapper(sources[0], targets ? targets[0] : anyType, sources[1], targets ? targets[1] : anyType) :
79747981 makeArrayTypeMapper(sources, targets);
79757982 mapper.mappedTypes = sources;
79767983 return mapper;
79777984 }
79787985
7979- function createTypeEraser(sources: Type []): TypeMapper {
7986+ function createTypeEraser(sources: TypeParameter []): TypeMapper {
79807987 return createTypeMapper(sources, /*targets*/ undefined);
79817988 }
79827989
@@ -10628,7 +10635,7 @@ namespace ts {
1062810635 context));
1062910636 }
1063010637 else {
10631- inferredType = context.flags & InferenceFlags.AnyDefault ? anyType : emptyObjectType ;
10638+ inferredType = getDefaultTypeArgumentType(!!( context.flags & InferenceFlags.AnyDefault)) ;
1063210639 }
1063310640 }
1063410641 inference.inferredType = inferredType;
@@ -10644,6 +10651,10 @@ namespace ts {
1064410651 return inferredType;
1064510652 }
1064610653
10654+ function getDefaultTypeArgumentType(isInJavaScriptFile: boolean): Type {
10655+ return isInJavaScriptFile ? anyType : emptyObjectType;
10656+ }
10657+
1064710658 function getInferredTypes(context: InferenceContext): Type[] {
1064810659 const result: Type[] = [];
1064910660 for (let i = 0; i < context.inferences.length; i++) {
@@ -12787,7 +12798,9 @@ namespace ts {
1278712798 const args = getEffectiveCallArguments(callTarget);
1278812799 const argIndex = indexOf(args, arg);
1278912800 if (argIndex >= 0) {
12790- const signature = getResolvedOrAnySignature(callTarget);
12801+ // If we're already in the process of resolving the given signature, don't resolve again as
12802+ // that could cause infinite recursion. Instead, return anySignature.
12803+ const signature = getNodeLinks(callTarget).resolvedSignature === resolvingSignature ? resolvingSignature : getResolvedSignature(callTarget);
1279112804 return getTypeAtPosition(signature, argIndex);
1279212805 }
1279312806 return undefined;
@@ -14962,16 +14975,14 @@ namespace ts {
1496214975 }
1496314976
1496414977 function inferTypeArguments(node: CallLikeExpression, signature: Signature, args: Expression[], excludeArgument: boolean[], context: InferenceContext): Type[] {
14965- const inferences = context.inferences;
14966-
1496714978 // Clear out all the inference results from the last time inferTypeArguments was called on this context
14968- for (let i = 0; i < inferences.length; i++ ) {
14979+ for (const inference of context.inferences ) {
1496914980 // As an optimization, we don't have to clear (and later recompute) inferred types
1497014981 // for type parameters that have already been fixed on the previous call to inferTypeArguments.
1497114982 // It would be just as correct to reset all of them. But then we'd be repeating the same work
1497214983 // for the type parameters that were fixed, namely the work done by getInferredType.
14973- if (!inferences[i] .isFixed) {
14974- inferences[i] .inferredType = undefined;
14984+ if (!inference .isFixed) {
14985+ inference .inferredType = undefined;
1497514986 }
1497614987 }
1497714988
@@ -15640,27 +15651,43 @@ namespace ts {
1564015651 }
1564115652
1564215653 // No signature was applicable. We have already reported the errors for the invalid signature.
15643- // If this is a type resolution session, e.g. Language Service, try to get better information that anySignature.
15644- // Pick the first candidate that matches the arity. This way we can get a contextual type for cases like:
15645- // declare function f(a: { xa: number; xb: number; });
15646- // f({ |
15654+ // If this is a type resolution session, e.g. Language Service, try to get better information than anySignature.
15655+ // Pick the longest signature. This way we can get a contextual type for cases like:
15656+ // declare function f(a: { xa: number; xb: number; }, b: number);
15657+ // f({ |
15658+ // Also, use explicitly-supplied type arguments if they are provided, so we can get a contextual signature in cases like:
15659+ // declare function f<T>(k: keyof T);
15660+ // f<Foo>("
1564715661 if (!produceDiagnostics) {
15648- for (let candidate of candidates) {
15649- if (hasCorrectArity(node, args, candidate)) {
15650- if (candidate.typeParameters && typeArguments) {
15651- candidate = getSignatureInstantiation(candidate, map(typeArguments, getTypeFromTypeNode));
15652- }
15653- return candidate;
15662+ Debug.assert(candidates.length > 0); // Else would have exited above.
15663+ const bestIndex = getLongestCandidateIndex(candidates, apparentArgumentCount === undefined ? args.length : apparentArgumentCount);
15664+ const candidate = candidates[bestIndex];
15665+
15666+ const { typeParameters } = candidate;
15667+ if (typeParameters && callLikeExpressionMayHaveTypeArguments(node) && node.typeArguments) {
15668+ const typeArguments = node.typeArguments.map(getTypeOfNode);
15669+ while (typeArguments.length > typeParameters.length) {
15670+ typeArguments.pop();
15671+ }
15672+ while (typeArguments.length < typeParameters.length) {
15673+ typeArguments.push(getDefaultTypeArgumentType(isInJavaScriptFile(node)));
1565415674 }
15675+
15676+ const instantiated = createSignatureInstantiation(candidate, typeArguments);
15677+ candidates[bestIndex] = instantiated;
15678+ return instantiated;
1565515679 }
15680+
15681+ return candidate;
1565615682 }
1565715683
1565815684 return resolveErrorCall(node);
1565915685
1566015686 function chooseOverload(candidates: Signature[], relation: Map<RelationComparisonResult>, signatureHelpTrailingComma = false) {
1566115687 candidateForArgumentError = undefined;
1566215688 candidateForTypeArgumentError = undefined;
15663- for (const originalCandidate of candidates) {
15689+ for (let candidateIndex = 0; candidateIndex < candidates.length; candidateIndex++) {
15690+ const originalCandidate = candidates[candidateIndex];
1566415691 if (!hasCorrectArity(node, args, originalCandidate, signatureHelpTrailingComma)) {
1566515692 continue;
1566615693 }
@@ -15692,6 +15719,7 @@ namespace ts {
1569215719 }
1569315720 const index = excludeArgument ? indexOf(excludeArgument, /*value*/ true) : -1;
1569415721 if (index < 0) {
15722+ candidates[candidateIndex] = candidate;
1569515723 return candidate;
1569615724 }
1569715725 excludeArgument[index] = false;
@@ -15703,6 +15731,24 @@ namespace ts {
1570315731
1570415732 }
1570515733
15734+ function getLongestCandidateIndex(candidates: Signature[], argsCount: number): number {
15735+ let maxParamsIndex = -1;
15736+ let maxParams = -1;
15737+
15738+ for (let i = 0; i < candidates.length; i++) {
15739+ const candidate = candidates[i];
15740+ if (candidate.hasRestParameter || candidate.parameters.length >= argsCount) {
15741+ return i;
15742+ }
15743+ if (candidate.parameters.length > maxParams) {
15744+ maxParams = candidate.parameters.length;
15745+ maxParamsIndex = i;
15746+ }
15747+ }
15748+
15749+ return maxParamsIndex;
15750+ }
15751+
1570615752 function resolveCallExpression(node: CallExpression, candidatesOutArray: Signature[]): Signature {
1570715753 if (node.expression.kind === SyntaxKind.SuperKeyword) {
1570815754 const superType = checkSuperExpression(node.expression);
@@ -16017,9 +16063,7 @@ namespace ts {
1601716063
1601816064 const callSignatures = elementType && getSignaturesOfType(elementType, SignatureKind.Call);
1601916065 if (callSignatures && callSignatures.length > 0) {
16020- let callSignature: Signature;
16021- callSignature = resolveCall(openingLikeElement, callSignatures, candidatesOutArray);
16022- return callSignature;
16066+ return resolveCall(openingLikeElement, callSignatures, candidatesOutArray);
1602316067 }
1602416068
1602516069 return undefined;
@@ -16069,12 +16113,6 @@ namespace ts {
1606916113 return result;
1607016114 }
1607116115
16072- function getResolvedOrAnySignature(node: CallLikeExpression) {
16073- // If we're already in the process of resolving the given signature, don't resolve again as
16074- // that could cause infinite recursion. Instead, return anySignature.
16075- return getNodeLinks(node).resolvedSignature === resolvingSignature ? resolvingSignature : getResolvedSignature(node);
16076- }
16077-
1607816116 /**
1607916117 * Indicates whether a declaration can be treated as a constructor in a JavaScript
1608016118 * file.
0 commit comments