@@ -6682,13 +6682,17 @@ namespace ts {
6682
6682
}
6683
6683
6684
6684
function getRestTypeOfSignature(signature: Signature): Type {
6685
+ return tryGetRestTypeOfSignature(signature) || anyType;
6686
+ }
6687
+
6688
+ function tryGetRestTypeOfSignature(signature: Signature): Type | undefined {
6685
6689
if (signature.hasRestParameter) {
6686
6690
const type = getTypeOfSymbol(lastOrUndefined(signature.parameters));
6687
6691
if (getObjectFlags(type) & ObjectFlags.Reference && (<TypeReference>type).target === globalArrayType) {
6688
6692
return (<TypeReference>type).typeArguments[0];
6689
6693
}
6690
6694
}
6691
- return anyType ;
6695
+ return undefined ;
6692
6696
}
6693
6697
6694
6698
function getSignatureInstantiation(signature: Signature, typeArguments: Type[], isJavascript: boolean): Signature {
@@ -10430,6 +10434,11 @@ namespace ts {
10430
10434
return symbol;
10431
10435
}
10432
10436
10437
+ function createCombinedSymbolWithType(sources: ReadonlyArray<Symbol>, type: Type): Symbol {
10438
+ // This function is currently only used for erroneous overloads, so it's good enough to just use the first source.
10439
+ return createSymbolWithType(first(sources), type);
10440
+ }
10441
+
10433
10442
function transformTypeOfMembers(type: Type, f: (propertyType: Type) => Type) {
10434
10443
const members = createSymbolTable();
10435
10444
for (const property of getPropertiesOfObjectType(type)) {
@@ -16433,35 +16442,8 @@ namespace ts {
16433
16442
diagnostics.add(createDiagnosticForNode(node, fallbackError));
16434
16443
}
16435
16444
16436
- // No signature was applicable. We have already reported the errors for the invalid signature.
16437
- // If this is a type resolution session, e.g. Language Service, try to get better information than anySignature.
16438
- // Pick the longest signature. This way we can get a contextual type for cases like:
16439
- // declare function f(a: { xa: number; xb: number; }, b: number);
16440
- // f({ |
16441
- // Also, use explicitly-supplied type arguments if they are provided, so we can get a contextual signature in cases like:
16442
- // declare function f<T>(k: keyof T);
16443
- // f<Foo>("
16444
16445
if (!produceDiagnostics) {
16445
- Debug.assert(candidates.length > 0); // Else would have exited above.
16446
- const bestIndex = getLongestCandidateIndex(candidates, apparentArgumentCount === undefined ? args.length : apparentArgumentCount);
16447
- const candidate = candidates[bestIndex];
16448
-
16449
- const { typeParameters } = candidate;
16450
- if (typeParameters && callLikeExpressionMayHaveTypeArguments(node) && node.typeArguments) {
16451
- const typeArguments = node.typeArguments.map(getTypeOfNode);
16452
- while (typeArguments.length > typeParameters.length) {
16453
- typeArguments.pop();
16454
- }
16455
- while (typeArguments.length < typeParameters.length) {
16456
- typeArguments.push(getDefaultTypeArgumentType(isInJavaScriptFile(node)));
16457
- }
16458
-
16459
- const instantiated = createSignatureInstantiation(candidate, typeArguments);
16460
- candidates[bestIndex] = instantiated;
16461
- return instantiated;
16462
- }
16463
-
16464
- return candidate;
16446
+ return getCandidateForOverloadFailure(node, candidates, args, !!candidatesOutArray);
16465
16447
}
16466
16448
16467
16449
return resolveErrorCall(node);
@@ -16535,6 +16517,89 @@ namespace ts {
16535
16517
}
16536
16518
}
16537
16519
16520
+ // No signature was applicable. We have already reported the errors for the invalid signature.
16521
+ // If this is a type resolution session, e.g. Language Service, try to get better information than anySignature.
16522
+ function getCandidateForOverloadFailure(
16523
+ node: CallLikeExpression,
16524
+ candidates: Signature[],
16525
+ args: ReadonlyArray<Expression>,
16526
+ hasCandidatesOutArray: boolean,
16527
+ ): Signature {
16528
+ Debug.assert(candidates.length > 0); // Else should not have called this.
16529
+
16530
+ // Normally we will combine overloads. Skip this if they have type parameters since that's hard to combine.
16531
+ // Don't do this if there is a `candidatesOutArray`,
16532
+ // because then we want the chosen best candidate to be one of the overloads, not a combination.
16533
+ if (!hasCandidatesOutArray && candidates.length > 1 && !candidates.some(c => !!c.typeParameters)) {
16534
+ return createUnionOfSignaturesForOverloadFailure(candidates);
16535
+ }
16536
+
16537
+ // Pick the longest signature. This way we can get a contextual type for cases like:
16538
+ // declare function f(a: { xa: number; xb: number; }, b: number);
16539
+ // f({ |
16540
+ // Also, use explicitly-supplied type arguments if they are provided, so we can get a contextual signature in cases like:
16541
+ // declare function f<T>(k: keyof T);
16542
+ // f<Foo>("
16543
+ const bestIndex = getLongestCandidateIndex(candidates, apparentArgumentCount === undefined ? args.length : apparentArgumentCount);
16544
+ const candidate = candidates[bestIndex];
16545
+
16546
+ const { typeParameters } = candidate;
16547
+ if (typeParameters && callLikeExpressionMayHaveTypeArguments(node) && node.typeArguments) {
16548
+ const typeArguments = node.typeArguments.map(getTypeOfNode);
16549
+ while (typeArguments.length > typeParameters.length) {
16550
+ typeArguments.pop();
16551
+ }
16552
+ while (typeArguments.length < typeParameters.length) {
16553
+ typeArguments.push(getDefaultTypeArgumentType(isInJavaScriptFile(node)));
16554
+ }
16555
+
16556
+ const instantiated = createSignatureInstantiation(candidate, typeArguments);
16557
+ candidates[bestIndex] = instantiated;
16558
+ return instantiated;
16559
+ }
16560
+
16561
+ return candidate;
16562
+ }
16563
+
16564
+ function createUnionOfSignaturesForOverloadFailure(candidates: ReadonlyArray<Signature>): Signature {
16565
+ const thisParameters = mapDefined(candidates, c => c.thisParameter);
16566
+ let thisParameter: Symbol | undefined;
16567
+ if (thisParameters.length) {
16568
+ thisParameter = createCombinedSymbolWithType(thisParameters, getUnionType(thisParameters.map(getTypeOfParameter), /*subtypeReduction*/ true));
16569
+ }
16570
+
16571
+ const { min: minArgumentCount, max: maxNonRestParam } = minAndMax(candidates, getNumNonRestParameters);
16572
+ const hasRestParameter = candidates.some(c => c.hasRestParameter);
16573
+ const hasLiteralTypes = candidates.some(c => c.hasLiteralTypes);
16574
+ const parameters: ts.Symbol[] = [];
16575
+ for (let i = 0; i < maxNonRestParam; i++) {
16576
+ const symbols = mapDefined(candidates, ({ parameters, hasRestParameter }) => hasRestParameter ?
16577
+ i < parameters.length - 1 ? parameters[i] : last(parameters) :
16578
+ i < parameters.length ? parameters[i] : undefined);
16579
+ Debug.assert(symbols.length !== 0);
16580
+ const types = mapDefined(candidates, candidate => tryGetTypeAtPosition(candidate, i));
16581
+ parameters.push(createCombinedSymbolWithType(symbols, getUnionType(types, /*subtypeReduction*/ true)));
16582
+ }
16583
+
16584
+ if (hasRestParameter) {
16585
+ const symbols = mapDefined(candidates, c => c.hasRestParameter ? last(c.parameters) : undefined);
16586
+ Debug.assert(symbols.length !== 0);
16587
+ const type = createArrayType(getUnionType(mapDefined(candidates, tryGetRestTypeOfSignature), /*subtypeReduction*/ true));
16588
+ parameters.push(createCombinedSymbolWithType(symbols, type));
16589
+ }
16590
+
16591
+ return createSignature(
16592
+ candidates[0].declaration,
16593
+ /*typeParameters*/ undefined,
16594
+ thisParameter,
16595
+ parameters,
16596
+ /*resolvedReturnType*/ unknownType,
16597
+ /*typePredicate*/ undefined,
16598
+ minArgumentCount,
16599
+ hasRestParameter,
16600
+ hasLiteralTypes);
16601
+ }
16602
+
16538
16603
function getLongestCandidateIndex(candidates: Signature[], argsCount: number): number {
16539
16604
let maxParamsIndex = -1;
16540
16605
let maxParams = -1;
@@ -17175,9 +17240,13 @@ namespace ts {
17175
17240
}
17176
17241
17177
17242
function getTypeAtPosition(signature: Signature, pos: number): Type {
17243
+ return tryGetTypeAtPosition(signature, pos) || anyType;
17244
+ }
17245
+
17246
+ function tryGetTypeAtPosition(signature: Signature, pos: number): Type | undefined {
17178
17247
return signature.hasRestParameter ?
17179
17248
pos < signature.parameters.length - 1 ? getTypeOfParameter(signature.parameters[pos]) : getRestTypeOfSignature(signature) :
17180
- pos < signature.parameters.length ? getTypeOfParameter(signature.parameters[pos]) : anyType ;
17249
+ pos < signature.parameters.length ? getTypeOfParameter(signature.parameters[pos]) : undefined ;
17181
17250
}
17182
17251
17183
17252
function getTypeOfFirstParameterOfSignature(signature: Signature) {
0 commit comments