@@ -7602,9 +7602,13 @@ namespace ts {
7602
7602
return !signature.resolvedReturnType && findResolutionCycleStartIndex(signature, TypeSystemPropertyName.ResolvedReturnType) >= 0;
7603
7603
}
7604
7604
7605
- function getRestTypeOfSignature(signature: Signature) {
7605
+ function getRestTypeOfSignature(signature: Signature): Type {
7606
+ return tryGetRestTypeOfSignature(signature) || anyType;
7607
+ }
7608
+
7609
+ function tryGetRestTypeOfSignature(signature: Signature): Type | undefined {
7606
7610
const type = getTypeOfRestParameter(signature);
7607
- return type && getIndexTypeOfType(type, IndexKind.Number) || anyType ;
7611
+ return type && getIndexTypeOfType(type, IndexKind.Number);
7608
7612
}
7609
7613
7610
7614
function getSignatureInstantiation(signature: Signature, typeArguments: Type[] | undefined, isJavascript: boolean): Signature {
@@ -18769,38 +18773,7 @@ namespace ts {
18769
18773
diagnostics.add(createDiagnosticForNode(node, fallbackError));
18770
18774
}
18771
18775
18772
- // No signature was applicable. We have already reported the errors for the invalid signature.
18773
- // If this is a type resolution session, e.g. Language Service, try to get better information than anySignature.
18774
- // Pick the longest signature. This way we can get a contextual type for cases like:
18775
- // declare function f(a: { xa: number; xb: number; }, b: number);
18776
- // f({ |
18777
- // Also, use explicitly-supplied type arguments if they are provided, so we can get a contextual signature in cases like:
18778
- // declare function f<T>(k: keyof T);
18779
- // f<Foo>("
18780
- if (!produceDiagnostics) {
18781
- Debug.assert(candidates.length > 0); // Else would have exited above.
18782
- const bestIndex = getLongestCandidateIndex(candidates, apparentArgumentCount === undefined ? args!.length : apparentArgumentCount);
18783
- const candidate = candidates[bestIndex];
18784
-
18785
- const { typeParameters } = candidate;
18786
- if (typeParameters && callLikeExpressionMayHaveTypeArguments(node) && node.typeArguments) {
18787
- const typeArguments = node.typeArguments.map(getTypeOfNode) as Type[]; // TODO: GH#18217
18788
- while (typeArguments.length > typeParameters.length) {
18789
- typeArguments.pop();
18790
- }
18791
- while (typeArguments.length < typeParameters.length) {
18792
- typeArguments.push(getDefaultTypeArgumentType(isInJavaScriptFile(node)));
18793
- }
18794
-
18795
- const instantiated = createSignatureInstantiation(candidate, typeArguments);
18796
- candidates[bestIndex] = instantiated;
18797
- return instantiated;
18798
- }
18799
-
18800
- return candidate;
18801
- }
18802
-
18803
- return resolveErrorCall(node);
18776
+ return produceDiagnostics || !args ? resolveErrorCall(node) : getCandidateForOverloadFailure(node, candidates, args, !!candidatesOutArray);
18804
18777
18805
18778
function chooseOverload(candidates: Signature[], relation: Map<RelationComparisonResult>, signatureHelpTrailingComma = false) {
18806
18779
candidateForArgumentError = undefined;
@@ -18871,6 +18844,97 @@ namespace ts {
18871
18844
}
18872
18845
}
18873
18846
18847
+ // No signature was applicable. We have already reported the errors for the invalid signature.
18848
+ // If this is a type resolution session, e.g. Language Service, try to get better information than anySignature.
18849
+ function getCandidateForOverloadFailure(
18850
+ node: CallLikeExpression,
18851
+ candidates: Signature[],
18852
+ args: ReadonlyArray<Expression>,
18853
+ hasCandidatesOutArray: boolean,
18854
+ ): Signature {
18855
+ Debug.assert(candidates.length > 0); // Else should not have called this.
18856
+ // Normally we will combine overloads. Skip this if they have type parameters since that's hard to combine.
18857
+ // Don't do this if there is a `candidatesOutArray`,
18858
+ // because then we want the chosen best candidate to be one of the overloads, not a combination.
18859
+ return hasCandidatesOutArray || candidates.length === 1 || candidates.some(c => !!c.typeParameters)
18860
+ ? pickLongestCandidateSignature(node, candidates, args)
18861
+ : createUnionOfSignaturesForOverloadFailure(candidates);
18862
+ }
18863
+
18864
+ function createUnionOfSignaturesForOverloadFailure(candidates: ReadonlyArray<Signature>): Signature {
18865
+ const thisParameters = mapDefined(candidates, c => c.thisParameter);
18866
+ let thisParameter: Symbol | undefined;
18867
+ if (thisParameters.length) {
18868
+ thisParameter = createCombinedSymbolFromTypes(thisParameters, thisParameters.map(getTypeOfParameter));
18869
+ }
18870
+ const { min: minArgumentCount, max: maxNonRestParam } = minAndMax(candidates, getNumNonRestParameters);
18871
+ const parameters: Symbol[] = [];
18872
+ for (let i = 0; i < maxNonRestParam; i++) {
18873
+ const symbols = mapDefined(candidates, ({ parameters, hasRestParameter }) => hasRestParameter ?
18874
+ i < parameters.length - 1 ? parameters[i] : last(parameters) :
18875
+ i < parameters.length ? parameters[i] : undefined);
18876
+ Debug.assert(symbols.length !== 0);
18877
+ parameters.push(createCombinedSymbolFromTypes(symbols, mapDefined(candidates, candidate => tryGetTypeAtPosition(candidate, i))));
18878
+ }
18879
+ const restParameterSymbols = mapDefined(candidates, c => c.hasRestParameter ? last(c.parameters) : undefined);
18880
+ const hasRestParameter = restParameterSymbols.length !== 0;
18881
+ if (hasRestParameter) {
18882
+ const type = createArrayType(getUnionType(mapDefined(candidates, tryGetRestTypeOfSignature), UnionReduction.Subtype));
18883
+ parameters.push(createCombinedSymbolForOverloadFailure(restParameterSymbols, type));
18884
+ }
18885
+ return createSignature(
18886
+ candidates[0].declaration,
18887
+ /*typeParameters*/ undefined, // Before calling this we tested for `!candidates.some(c => !!c.typeParameters)`.
18888
+ thisParameter,
18889
+ parameters,
18890
+ /*resolvedReturnType*/ getIntersectionType(candidates.map(getReturnTypeOfSignature)),
18891
+ /*typePredicate*/ undefined,
18892
+ minArgumentCount,
18893
+ hasRestParameter,
18894
+ /*hasLiteralTypes*/ candidates.some(c => c.hasLiteralTypes));
18895
+ }
18896
+
18897
+ function getNumNonRestParameters(signature: Signature): number {
18898
+ const numParams = signature.parameters.length;
18899
+ return signature.hasRestParameter ? numParams - 1 : numParams;
18900
+ }
18901
+
18902
+ function createCombinedSymbolFromTypes(sources: ReadonlyArray<Symbol>, types: Type[]): Symbol {
18903
+ return createCombinedSymbolForOverloadFailure(sources, getUnionType(types, UnionReduction.Subtype));
18904
+ }
18905
+
18906
+ function createCombinedSymbolForOverloadFailure(sources: ReadonlyArray<Symbol>, type: Type): Symbol {
18907
+ // This function is currently only used for erroneous overloads, so it's good enough to just use the first source.
18908
+ return createSymbolWithType(first(sources), type);
18909
+ }
18910
+
18911
+ function pickLongestCandidateSignature(node: CallLikeExpression, candidates: Signature[], args: ReadonlyArray<Expression>): Signature {
18912
+ // Pick the longest signature. This way we can get a contextual type for cases like:
18913
+ // declare function f(a: { xa: number; xb: number; }, b: number);
18914
+ // f({ |
18915
+ // Also, use explicitly-supplied type arguments if they are provided, so we can get a contextual signature in cases like:
18916
+ // declare function f<T>(k: keyof T);
18917
+ // f<Foo>("
18918
+ const bestIndex = getLongestCandidateIndex(candidates, apparentArgumentCount === undefined ? args.length : apparentArgumentCount);
18919
+ const candidate = candidates[bestIndex];
18920
+ const { typeParameters } = candidate;
18921
+ if (!typeParameters) {
18922
+ return candidate;
18923
+ }
18924
+
18925
+ const typeArgumentNodes: ReadonlyArray<TypeNode> = callLikeExpressionMayHaveTypeArguments(node) ? node.typeArguments || emptyArray : emptyArray;
18926
+ const typeArguments = typeArgumentNodes.map(n => getTypeOfNode(n) || anyType);
18927
+ while (typeArguments.length > typeParameters.length) {
18928
+ typeArguments.pop();
18929
+ }
18930
+ while (typeArguments.length < typeParameters.length) {
18931
+ typeArguments.push(getConstraintFromTypeParameter(typeParameters[typeArguments.length]) || getDefaultTypeArgumentType(isInJavaScriptFile(node)));
18932
+ }
18933
+ const instantiated = createSignatureInstantiation(candidate, typeArguments);
18934
+ candidates[bestIndex] = instantiated;
18935
+ return instantiated;
18936
+ }
18937
+
18874
18938
function getLongestCandidateIndex(candidates: Signature[], argsCount: number): number {
18875
18939
let maxParamsIndex = -1;
18876
18940
let maxParams = -1;
@@ -19626,6 +19690,10 @@ namespace ts {
19626
19690
}
19627
19691
19628
19692
function getTypeAtPosition(signature: Signature, pos: number): Type {
19693
+ return tryGetTypeAtPosition(signature, pos) || anyType;
19694
+ }
19695
+
19696
+ function tryGetTypeAtPosition(signature: Signature, pos: number): Type | undefined {
19629
19697
const paramCount = signature.parameters.length - (signature.hasRestParameter ? 1 : 0);
19630
19698
if (pos < paramCount) {
19631
19699
return getTypeOfParameter(signature.parameters[pos]);
@@ -19641,9 +19709,9 @@ namespace ts {
19641
19709
return tupleRestType;
19642
19710
}
19643
19711
}
19644
- return getIndexTypeOfType(restType, IndexKind.Number) || anyType ;
19712
+ return getIndexTypeOfType(restType, IndexKind.Number);
19645
19713
}
19646
- return anyType ;
19714
+ return undefined ;
19647
19715
}
19648
19716
19649
19717
function getTypeOfRestParameter(signature: Signature) {
0 commit comments