@@ -75,6 +75,9 @@ namespace ts {
75
75
undefinedSymbol.declarations = [];
76
76
const argumentsSymbol = createSymbol(SymbolFlags.Property, "arguments");
77
77
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
+
78
81
// for public members that accept a Node or one of its subtypes, we must guard against
79
82
// synthetic nodes created during transformations by calling `getParseTreeNode`.
80
83
// for most of these, we perform the guard only on `checker` to avoid any possible
@@ -160,9 +163,12 @@ namespace ts {
160
163
return node ? getContextualType(node) : undefined;
161
164
},
162
165
getFullyQualifiedName,
163
- getResolvedSignature: (node, candidatesOutArray? ) => {
166
+ getResolvedSignature: (node, candidatesOutArray, theArgumentCount ) => {
164
167
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;
166
172
},
167
173
getConstantValue: node => {
168
174
node = getParseTreeNode(node, canHaveConstantValue);
@@ -6313,12 +6319,12 @@ namespace ts {
6313
6319
// If a type parameter does not have a default type, or if the default type
6314
6320
// is a forward reference, the empty object type is used.
6315
6321
for (let i = numTypeArguments; i < numTypeParameters; i++) {
6316
- typeArguments[i] = isJavaScript ? anyType : emptyObjectType ;
6322
+ typeArguments[i] = getDefaultTypeArgumentType( isJavaScript) ;
6317
6323
}
6318
6324
for (let i = numTypeArguments; i < numTypeParameters; i++) {
6319
6325
const mapper = createTypeMapper(typeParameters, typeArguments);
6320
6326
const defaultType = getDefaultFromTypeParameter(typeParameters[i]);
6321
- typeArguments[i] = defaultType ? instantiateType(defaultType, mapper) : isJavaScript ? anyType : emptyObjectType ;
6327
+ typeArguments[i] = defaultType ? instantiateType(defaultType, mapper) : getDefaultTypeArgumentType( isJavaScript) ;
6322
6328
}
6323
6329
}
6324
6330
}
@@ -7968,15 +7974,16 @@ namespace ts {
7968
7974
};
7969
7975
}
7970
7976
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);
7972
7979
const mapper: TypeMapper = sources.length === 1 ? makeUnaryTypeMapper(sources[0], targets ? targets[0] : anyType) :
7973
7980
sources.length === 2 ? makeBinaryTypeMapper(sources[0], targets ? targets[0] : anyType, sources[1], targets ? targets[1] : anyType) :
7974
7981
makeArrayTypeMapper(sources, targets);
7975
7982
mapper.mappedTypes = sources;
7976
7983
return mapper;
7977
7984
}
7978
7985
7979
- function createTypeEraser(sources: Type []): TypeMapper {
7986
+ function createTypeEraser(sources: TypeParameter []): TypeMapper {
7980
7987
return createTypeMapper(sources, /*targets*/ undefined);
7981
7988
}
7982
7989
@@ -10628,7 +10635,7 @@ namespace ts {
10628
10635
context));
10629
10636
}
10630
10637
else {
10631
- inferredType = context.flags & InferenceFlags.AnyDefault ? anyType : emptyObjectType ;
10638
+ inferredType = getDefaultTypeArgumentType(!!( context.flags & InferenceFlags.AnyDefault)) ;
10632
10639
}
10633
10640
}
10634
10641
inference.inferredType = inferredType;
@@ -10644,6 +10651,10 @@ namespace ts {
10644
10651
return inferredType;
10645
10652
}
10646
10653
10654
+ function getDefaultTypeArgumentType(isInJavaScriptFile: boolean): Type {
10655
+ return isInJavaScriptFile ? anyType : emptyObjectType;
10656
+ }
10657
+
10647
10658
function getInferredTypes(context: InferenceContext): Type[] {
10648
10659
const result: Type[] = [];
10649
10660
for (let i = 0; i < context.inferences.length; i++) {
@@ -12787,7 +12798,9 @@ namespace ts {
12787
12798
const args = getEffectiveCallArguments(callTarget);
12788
12799
const argIndex = indexOf(args, arg);
12789
12800
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);
12791
12804
return getTypeAtPosition(signature, argIndex);
12792
12805
}
12793
12806
return undefined;
@@ -14962,16 +14975,14 @@ namespace ts {
14962
14975
}
14963
14976
14964
14977
function inferTypeArguments(node: CallLikeExpression, signature: Signature, args: Expression[], excludeArgument: boolean[], context: InferenceContext): Type[] {
14965
- const inferences = context.inferences;
14966
-
14967
14978
// 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 ) {
14969
14980
// As an optimization, we don't have to clear (and later recompute) inferred types
14970
14981
// for type parameters that have already been fixed on the previous call to inferTypeArguments.
14971
14982
// It would be just as correct to reset all of them. But then we'd be repeating the same work
14972
14983
// 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;
14975
14986
}
14976
14987
}
14977
14988
@@ -15640,27 +15651,43 @@ namespace ts {
15640
15651
}
15641
15652
15642
15653
// 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>("
15647
15661
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)));
15654
15674
}
15675
+
15676
+ const instantiated = createSignatureInstantiation(candidate, typeArguments);
15677
+ candidates[bestIndex] = instantiated;
15678
+ return instantiated;
15655
15679
}
15680
+
15681
+ return candidate;
15656
15682
}
15657
15683
15658
15684
return resolveErrorCall(node);
15659
15685
15660
15686
function chooseOverload(candidates: Signature[], relation: Map<RelationComparisonResult>, signatureHelpTrailingComma = false) {
15661
15687
candidateForArgumentError = undefined;
15662
15688
candidateForTypeArgumentError = undefined;
15663
- for (const originalCandidate of candidates) {
15689
+ for (let candidateIndex = 0; candidateIndex < candidates.length; candidateIndex++) {
15690
+ const originalCandidate = candidates[candidateIndex];
15664
15691
if (!hasCorrectArity(node, args, originalCandidate, signatureHelpTrailingComma)) {
15665
15692
continue;
15666
15693
}
@@ -15692,6 +15719,7 @@ namespace ts {
15692
15719
}
15693
15720
const index = excludeArgument ? indexOf(excludeArgument, /*value*/ true) : -1;
15694
15721
if (index < 0) {
15722
+ candidates[candidateIndex] = candidate;
15695
15723
return candidate;
15696
15724
}
15697
15725
excludeArgument[index] = false;
@@ -15703,6 +15731,24 @@ namespace ts {
15703
15731
15704
15732
}
15705
15733
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
+
15706
15752
function resolveCallExpression(node: CallExpression, candidatesOutArray: Signature[]): Signature {
15707
15753
if (node.expression.kind === SyntaxKind.SuperKeyword) {
15708
15754
const superType = checkSuperExpression(node.expression);
@@ -16017,9 +16063,7 @@ namespace ts {
16017
16063
16018
16064
const callSignatures = elementType && getSignaturesOfType(elementType, SignatureKind.Call);
16019
16065
if (callSignatures && callSignatures.length > 0) {
16020
- let callSignature: Signature;
16021
- callSignature = resolveCall(openingLikeElement, callSignatures, candidatesOutArray);
16022
- return callSignature;
16066
+ return resolveCall(openingLikeElement, callSignatures, candidatesOutArray);
16023
16067
}
16024
16068
16025
16069
return undefined;
@@ -16069,12 +16113,6 @@ namespace ts {
16069
16113
return result;
16070
16114
}
16071
16115
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
-
16078
16116
/**
16079
16117
* Indicates whether a declaration can be treated as a constructor in a JavaScript
16080
16118
* file.
0 commit comments