Skip to content

Commit 71276a2

Browse files
committed
Merge branch 'master' into report-multiple-overload-errors
2 parents 9778474 + 410b717 commit 71276a2

File tree

99 files changed

+897
-352
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

99 files changed

+897
-352
lines changed

src/compiler/checker.ts

Lines changed: 121 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -21405,8 +21405,34 @@ namespace ts {
2140521405
return Debug.fail();
2140621406
}
2140721407
}
21408+
function getDiagnosticSpanForCallNode(node: CallExpression, doNotIncludeArguments?: boolean) {
21409+
let start: number;
21410+
let length: number;
21411+
const sourceFile = getSourceFileOfNode(node);
2140821412

21409-
function getArgumentArityError(node: Node, signatures: ReadonlyArray<Signature>, args: ReadonlyArray<Expression>) {
21413+
if (isPropertyAccessExpression(node.expression)) {
21414+
const nameSpan = getErrorSpanForNode(sourceFile, node.expression.name);
21415+
start = nameSpan.start;
21416+
length = doNotIncludeArguments ? nameSpan.length : node.end - start;
21417+
}
21418+
else {
21419+
const expressionSpan = getErrorSpanForNode(sourceFile, node.expression);
21420+
start = expressionSpan.start;
21421+
length = doNotIncludeArguments ? expressionSpan.length : node.end - start;
21422+
}
21423+
return { start, length, sourceFile };
21424+
}
21425+
function getDiagnosticForCallNode(node: CallLikeExpression, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number, arg3?: string | number): DiagnosticWithLocation {
21426+
if (isCallExpression(node)) {
21427+
const { sourceFile, start, length } = getDiagnosticSpanForCallNode(node);
21428+
return createFileDiagnostic(sourceFile, start, length, message, arg0, arg1, arg2, arg3);
21429+
}
21430+
else {
21431+
return createDiagnosticForNode(node, message, arg0, arg1, arg2, arg3);
21432+
}
21433+
}
21434+
21435+
function getArgumentArityError(node: CallLikeExpression, signatures: ReadonlyArray<Signature>, args: ReadonlyArray<Expression>) {
2141021436
let min = Number.POSITIVE_INFINITY;
2141121437
let max = Number.NEGATIVE_INFINITY;
2141221438
let belowArgCount = Number.NEGATIVE_INFINITY;
@@ -21453,11 +21479,11 @@ namespace ts {
2145321479
}
2145421480
}
2145521481
if (min < argCount && argCount < max) {
21456-
return createDiagnosticForNode(node, Diagnostics.No_overload_expects_0_arguments_but_overloads_do_exist_that_expect_either_1_or_2_arguments, argCount, belowArgCount, aboveArgCount);
21482+
return getDiagnosticForCallNode(node, Diagnostics.No_overload_expects_0_arguments_but_overloads_do_exist_that_expect_either_1_or_2_arguments, argCount, belowArgCount, aboveArgCount);
2145721483
}
2145821484

2145921485
if (!hasSpreadArgument && argCount < min) {
21460-
const diagnostic = createDiagnosticForNode(node, error, paramRange, argCount);
21486+
const diagnostic = getDiagnosticForCallNode(node, error, paramRange, argCount);
2146121487
return related ? addRelatedInfo(diagnostic, related) : diagnostic;
2146221488
}
2146321489

@@ -21532,8 +21558,7 @@ namespace ts {
2153221558
reorderCandidates(signatures, candidates);
2153321559
if (!candidates.length) {
2153421560
if (reportErrors) {
21535-
const errorNode = getCallErrorNode(node);
21536-
diagnostics.add(createDiagnosticForNode(errorNode, Diagnostics.Call_target_does_not_contain_any_signatures));
21561+
diagnostics.add(getDiagnosticForCallNode(node, Diagnostics.Call_target_does_not_contain_any_signatures));
2153721562
}
2153821563
return resolveErrorCall(node);
2153921564
}
@@ -21611,7 +21636,6 @@ namespace ts {
2161121636
// If candidate is undefined, it means that no candidates had a suitable arity. In that case,
2161221637
// skip the checkApplicableSignature check.
2161321638
if (reportErrors) {
21614-
const errorNode = getCallErrorNode(node);
2161521639
if (candidatesForArgumentError) {
2161621640
if (candidatesForArgumentError.length === 1 || candidatesForArgumentError.length > 3) {
2161721641
const last = candidatesForArgumentError[candidatesForArgumentError.length - 1];
@@ -21663,39 +21687,27 @@ namespace ts {
2166321687
}
2166421688
}
2166521689
else if (candidateForArgumentArityError) {
21666-
diagnostics.add(getArgumentArityError(errorNode, [candidateForArgumentArityError], args));
21690+
diagnostics.add(getArgumentArityError(node, [candidateForArgumentArityError], args));
2166721691
}
2166821692
else if (candidateForTypeArgumentError) {
2166921693
checkTypeArguments(candidateForTypeArgumentError, (node as CallExpression | TaggedTemplateExpression | JsxOpeningLikeElement).typeArguments!, /*reportErrors*/ true, fallbackError);
2167021694
}
2167121695
else {
2167221696
const signaturesWithCorrectTypeArgumentArity = filter(signatures, s => hasCorrectTypeArgumentArity(s, typeArguments));
2167321697
if (signaturesWithCorrectTypeArgumentArity.length === 0) {
21674-
diagnostics.add(getTypeArgumentArityError(errorNode, signatures, typeArguments!));
21698+
diagnostics.add(getTypeArgumentArityError(node, signatures, typeArguments!));
2167521699
}
2167621700
else if (!isDecorator) {
21677-
diagnostics.add(getArgumentArityError(errorNode, signaturesWithCorrectTypeArgumentArity, args));
21701+
diagnostics.add(getArgumentArityError(node, signaturesWithCorrectTypeArgumentArity, args));
2167821702
}
2167921703
else if (fallbackError) {
21680-
diagnostics.add(createDiagnosticForNode(errorNode, fallbackError));
21704+
diagnostics.add(getDiagnosticForCallNode(node, fallbackError));
2168121705
}
2168221706
}
2168321707
}
2168421708

2168521709
return produceDiagnostics || !args ? resolveErrorCall(node) : getCandidateForOverloadFailure(node, candidates, args, !!candidatesOutArray);
2168621710

21687-
function getCallErrorNode(node: CallLikeExpression): Node {
21688-
if (isCallExpression(node)) {
21689-
if (isPropertyAccessExpression(node.expression)) {
21690-
return node.expression.name;
21691-
}
21692-
else {
21693-
return node.expression;
21694-
}
21695-
}
21696-
return node;
21697-
}
21698-
2169921711
function chooseOverload(candidates: Signature[], relation: Map<RelationComparisonResult>, signatureHelpTrailingComma = false) {
2170021712
candidatesForArgumentError = undefined;
2170121713
candidateForArgumentArityError = undefined;
@@ -21974,7 +21986,7 @@ namespace ts {
2197421986
relatedInformation = createDiagnosticForNode(node.expression, Diagnostics.It_is_highly_likely_that_you_are_missing_a_semicolon);
2197521987
}
2197621988
}
21977-
invocationError(node, apparentType, SignatureKind.Call, relatedInformation);
21989+
invocationError(node.expression, apparentType, SignatureKind.Call, relatedInformation);
2197821990
}
2197921991
return resolveErrorCall(node);
2198021992
}
@@ -22091,7 +22103,7 @@ namespace ts {
2209122103
return signature;
2209222104
}
2209322105

22094-
invocationError(node, expressionType, SignatureKind.Construct);
22106+
invocationError(node.expression, expressionType, SignatureKind.Construct);
2209522107
return resolveErrorCall(node);
2209622108
}
2209722109

@@ -22164,11 +22176,88 @@ namespace ts {
2216422176
return true;
2216522177
}
2216622178

22167-
function invocationError(node: Node, apparentType: Type, kind: SignatureKind, relatedInformation?: DiagnosticRelatedInformation) {
22168-
const diagnostic = error(node, (kind === SignatureKind.Call ?
22169-
Diagnostics.Cannot_invoke_an_expression_whose_type_lacks_a_call_signature_Type_0_has_no_compatible_call_signatures :
22170-
Diagnostics.Cannot_use_new_with_an_expression_whose_type_lacks_a_call_or_construct_signature
22171-
), typeToString(apparentType));
22179+
function invocationErrorDetails(apparentType: Type, kind: SignatureKind): DiagnosticMessageChain {
22180+
let errorInfo: DiagnosticMessageChain | undefined;
22181+
const isCall = kind === SignatureKind.Call;
22182+
if (apparentType.flags & TypeFlags.Union) {
22183+
const types = (apparentType as UnionType).types;
22184+
let hasSignatures = false;
22185+
for (const constituent of types) {
22186+
const signatures = getSignaturesOfType(constituent, kind);
22187+
if (signatures.length !== 0) {
22188+
hasSignatures = true;
22189+
if (errorInfo) {
22190+
// Bail early if we already have an error, no chance of "No constituent of type is callable"
22191+
break;
22192+
}
22193+
}
22194+
else {
22195+
// Error on the first non callable constituent only
22196+
if (!errorInfo) {
22197+
errorInfo = chainDiagnosticMessages(
22198+
errorInfo,
22199+
isCall ?
22200+
Diagnostics.Type_0_has_no_call_signatures :
22201+
Diagnostics.Type_0_has_no_construct_signatures,
22202+
typeToString(constituent)
22203+
);
22204+
errorInfo = chainDiagnosticMessages(
22205+
errorInfo,
22206+
isCall ?
22207+
Diagnostics.Not_all_constituents_of_type_0_are_callable :
22208+
Diagnostics.Not_all_constituents_of_type_0_are_constructable,
22209+
typeToString(apparentType)
22210+
);
22211+
}
22212+
if (hasSignatures) {
22213+
// Bail early if we already found a siganture, no chance of "No constituent of type is callable"
22214+
break;
22215+
}
22216+
}
22217+
}
22218+
if (!hasSignatures) {
22219+
errorInfo = chainDiagnosticMessages(
22220+
/* detials */ undefined,
22221+
isCall ?
22222+
Diagnostics.No_constituent_of_type_0_is_callable :
22223+
Diagnostics.No_constituent_of_type_0_is_constructable,
22224+
typeToString(apparentType)
22225+
);
22226+
}
22227+
if (!errorInfo) {
22228+
errorInfo = chainDiagnosticMessages(
22229+
errorInfo,
22230+
isCall ?
22231+
Diagnostics.Each_member_of_the_union_type_0_has_signatures_but_none_of_those_signatures_are_compatible_with_each_other :
22232+
Diagnostics.Each_member_of_the_union_type_0_has_construct_signatures_but_none_of_those_signatures_are_compatible_with_each_other,
22233+
typeToString(apparentType)
22234+
);
22235+
}
22236+
}
22237+
else {
22238+
errorInfo = chainDiagnosticMessages(
22239+
errorInfo,
22240+
isCall ?
22241+
Diagnostics.Type_0_has_no_call_signatures :
22242+
Diagnostics.Type_0_has_no_construct_signatures,
22243+
typeToString(apparentType)
22244+
);
22245+
}
22246+
return chainDiagnosticMessages(
22247+
errorInfo,
22248+
isCall ?
22249+
Diagnostics.This_expression_is_not_callable :
22250+
Diagnostics.This_expression_is_not_constructable
22251+
);
22252+
}
22253+
function invocationError(errorTarget: Node, apparentType: Type, kind: SignatureKind, relatedInformation?: DiagnosticRelatedInformation) {
22254+
const diagnostic = createDiagnosticForNodeFromMessageChain(errorTarget, invocationErrorDetails(apparentType, kind));
22255+
if (isCallExpression(errorTarget.parent)) {
22256+
const { start, length } = getDiagnosticSpanForCallNode(errorTarget.parent, /* doNotIncludeArguments */ true);
22257+
diagnostic.start = start;
22258+
diagnostic.length = length;
22259+
}
22260+
diagnostics.add(diagnostic);
2217222261
invocationErrorRecovery(apparentType, kind, relatedInformation ? addRelatedInfo(diagnostic, relatedInformation) : diagnostic);
2217322262
}
2217422263

@@ -22206,7 +22295,7 @@ namespace ts {
2220622295
}
2220722296

2220822297
if (!callSignatures.length) {
22209-
invocationError(node, apparentType, SignatureKind.Call);
22298+
invocationError(node.tag, apparentType, SignatureKind.Call);
2221022299
return resolveErrorCall(node);
2221122300
}
2221222301

@@ -22262,9 +22351,9 @@ namespace ts {
2226222351

2226322352
const headMessage = getDiagnosticHeadMessageForDecoratorResolution(node);
2226422353
if (!callSignatures.length) {
22265-
let errorInfo = chainDiagnosticMessages(/*details*/ undefined, Diagnostics.Cannot_invoke_an_expression_whose_type_lacks_a_call_signature_Type_0_has_no_compatible_call_signatures, typeToString(apparentType));
22354+
let errorInfo = invocationErrorDetails(apparentType, SignatureKind.Call);
2226622355
errorInfo = chainDiagnosticMessages(errorInfo, headMessage);
22267-
const diag = createDiagnosticForNodeFromMessageChain(node, errorInfo);
22356+
const diag = createDiagnosticForNodeFromMessageChain(node.expression, errorInfo);
2226822357
diagnostics.add(diag);
2226922358
invocationErrorRecovery(apparentType, SignatureKind.Call, diag);
2227022359
return resolveErrorCall(node);

src/compiler/diagnosticMessages.json

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1236,15 +1236,15 @@
12361236
"category": "Error",
12371237
"code": 2348
12381238
},
1239-
"Cannot invoke an expression whose type lacks a call signature. Type '{0}' has no compatible call signatures.": {
1239+
"This expression is not callable.": {
12401240
"category": "Error",
12411241
"code": 2349
12421242
},
12431243
"Only a void function can be called with the 'new' keyword.": {
12441244
"category": "Error",
12451245
"code": 2350
12461246
},
1247-
"Cannot use 'new' with an expression whose type lacks a call or construct signature.": {
1247+
"This expression is not constructable.": {
12481248
"category": "Error",
12491249
"code": 2351
12501250
},
@@ -2621,22 +2621,54 @@
26212621
"category": "Error",
26222622
"code": 2754
26232623
},
2624-
"No overload matches this call.": {
2624+
"No constituent of type '{0}' is callable.": {
26252625
"category": "Error",
26262626
"code": 2755
26272627
},
2628-
"The last overload gave the following error.": {
2628+
"Not all constituents of type '{0}' are callable.": {
2629+
"category": "Error",
2630+
"code": 2756
2631+
},
2632+
"Type '{0}' has no call signatures.": {
2633+
"category": "Error",
2634+
"code": 2757
2635+
},
2636+
"Each member of the union type '{0}' has signatures, but none of those signatures are compatible with each other.": {
26292637
"category": "Error",
26302638
"code": 2758
26312639
},
2632-
"The last overload is declared here.": {
2640+
"No constituent of type '{0}' is constructable.": {
26332641
"category": "Error",
26342642
"code": 2759
26352643
},
2636-
"Overload {0} of {1}, '{2}', gave the following error.": {
2644+
"Not all constituents of type '{0}' are constructable.": {
26372645
"category": "Error",
26382646
"code": 2760
26392647
},
2648+
"Type '{0}' has no construct signatures.": {
2649+
"category": "Error",
2650+
"code": 2761
2651+
},
2652+
"Each member of the union type '{0}' has construct signatures, but none of those signatures are compatible with each other.": {
2653+
"category": "Error",
2654+
"code": 2762
2655+
},
2656+
"No overload matches this call.": {
2657+
"category": "Error",
2658+
"code": 2763
2659+
},
2660+
"The last overload gave the following error.": {
2661+
"category": "Error",
2662+
"code": 2764
2663+
},
2664+
"The last overload is declared here.": {
2665+
"category": "Error",
2666+
"code": 2765
2667+
},
2668+
"Overload {0} of {1}, '{2}', gave the following error.": {
2669+
"category": "Error",
2670+
"code": 2766
2671+
},
26402672

26412673
"Import declaration '{0}' is using private name '{1}'.": {
26422674
"category": "Error",

src/services/codefixes/fixInvalidImportSyntax.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,16 +31,16 @@ namespace ts.codefix {
3131

3232
registerCodeFix({
3333
errorCodes: [
34-
Diagnostics.Cannot_invoke_an_expression_whose_type_lacks_a_call_signature_Type_0_has_no_compatible_call_signatures.code,
35-
Diagnostics.Cannot_use_new_with_an_expression_whose_type_lacks_a_call_or_construct_signature.code,
34+
Diagnostics.This_expression_is_not_callable.code,
35+
Diagnostics.This_expression_is_not_constructable.code,
3636
],
3737
getCodeActions: getActionsForUsageOfInvalidImport
3838
});
3939

4040
function getActionsForUsageOfInvalidImport(context: CodeFixContext): CodeFixAction[] | undefined {
4141
const sourceFile = context.sourceFile;
42-
const targetKind = Diagnostics.Cannot_invoke_an_expression_whose_type_lacks_a_call_signature_Type_0_has_no_compatible_call_signatures.code === context.errorCode ? SyntaxKind.CallExpression : SyntaxKind.NewExpression;
43-
const node = findAncestor(getTokenAtPosition(sourceFile, context.span.start), a => a.kind === targetKind && a.getStart() === context.span.start && a.getEnd() === (context.span.start + context.span.length)) as CallExpression | NewExpression;
42+
const targetKind = Diagnostics.This_expression_is_not_callable.code === context.errorCode ? SyntaxKind.CallExpression : SyntaxKind.NewExpression;
43+
const node = findAncestor(getTokenAtPosition(sourceFile, context.span.start), a => a.kind === targetKind) as CallExpression | NewExpression;
4444
if (!node) {
4545
return [];
4646
}

tests/baselines/reference/arityErrorRelatedSpanBindingPattern.errors.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ tests/cases/compiler/arityErrorRelatedSpanBindingPattern.ts(7,1): error TS2554:
88
function bar(a, b, [c]): void {}
99

1010
foo("", 0);
11-
~~~
11+
~~~~~~~~~~
1212
!!! error TS2554: Expected 3 arguments, but got 2.
1313
!!! related TS6211 tests/cases/compiler/arityErrorRelatedSpanBindingPattern.ts:1:20: An argument matching this binding pattern was not provided.
1414

1515
bar("", 0);
16-
~~~
16+
~~~~~~~~~~
1717
!!! error TS2554: Expected 3 arguments, but got 2.
1818
!!! related TS6211 tests/cases/compiler/arityErrorRelatedSpanBindingPattern.ts:3:20: An argument matching this binding pattern was not provided.
1919

tests/baselines/reference/baseCheck.errors.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ tests/cases/compiler/baseCheck.ts(26,9): error TS2304: Cannot find name 'x'.
3030
}
3131

3232
class D extends C { constructor(public z: number) { super(this.z) } } // too few params
33-
~~~~~
33+
~~~~~~~~~~~~~
3434
!!! error TS2554: Expected 2 arguments, but got 1.
3535
!!! related TS6210 tests/cases/compiler/baseCheck.ts:1:34: An argument for 'y' was not provided.
3636
~~~~

0 commit comments

Comments
 (0)