@@ -21298,8 +21298,34 @@ namespace ts {
2129821298 return Debug.fail();
2129921299 }
2130021300 }
21301+ function getDiagnosticSpanForCallNode(node: CallExpression, doNotIncludeArguments?: boolean) {
21302+ let start: number;
21303+ let length: number;
21304+ const sourceFile = getSourceFileOfNode(node);
2130121305
21302- function getArgumentArityError(node: Node, signatures: ReadonlyArray<Signature>, args: ReadonlyArray<Expression>) {
21306+ if (isPropertyAccessExpression(node.expression)) {
21307+ const nameSpan = getErrorSpanForNode(sourceFile, node.expression.name);
21308+ start = nameSpan.start;
21309+ length = doNotIncludeArguments ? nameSpan.length : node.end - start;
21310+ }
21311+ else {
21312+ const expressionSpan = getErrorSpanForNode(sourceFile, node.expression);
21313+ start = expressionSpan.start;
21314+ length = doNotIncludeArguments ? expressionSpan.length : node.end - start;
21315+ }
21316+ return { start, length, sourceFile };
21317+ }
21318+ function getDiagnosticForCallNode(node: CallLikeExpression, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number, arg3?: string | number): DiagnosticWithLocation {
21319+ if (isCallExpression(node)) {
21320+ const { sourceFile, start, length } = getDiagnosticSpanForCallNode(node);
21321+ return createFileDiagnostic(sourceFile, start, length, message, arg0, arg1, arg2, arg3);
21322+ }
21323+ else {
21324+ return createDiagnosticForNode(node, message, arg0, arg1, arg2, arg3);
21325+ }
21326+ }
21327+
21328+ function getArgumentArityError(node: CallLikeExpression, signatures: ReadonlyArray<Signature>, args: ReadonlyArray<Expression>) {
2130321329 let min = Number.POSITIVE_INFINITY;
2130421330 let max = Number.NEGATIVE_INFINITY;
2130521331 let belowArgCount = Number.NEGATIVE_INFINITY;
@@ -21346,11 +21372,11 @@ namespace ts {
2134621372 }
2134721373 }
2134821374 if (min < argCount && argCount < max) {
21349- return createDiagnosticForNode (node, Diagnostics.No_overload_expects_0_arguments_but_overloads_do_exist_that_expect_either_1_or_2_arguments, argCount, belowArgCount, aboveArgCount);
21375+ return getDiagnosticForCallNode (node, Diagnostics.No_overload_expects_0_arguments_but_overloads_do_exist_that_expect_either_1_or_2_arguments, argCount, belowArgCount, aboveArgCount);
2135021376 }
2135121377
2135221378 if (!hasSpreadArgument && argCount < min) {
21353- const diagnostic = createDiagnosticForNode (node, error, paramRange, argCount);
21379+ const diagnostic = getDiagnosticForCallNode (node, error, paramRange, argCount);
2135421380 return related ? addRelatedInfo(diagnostic, related) : diagnostic;
2135521381 }
2135621382
@@ -21425,8 +21451,7 @@ namespace ts {
2142521451 reorderCandidates(signatures, candidates);
2142621452 if (!candidates.length) {
2142721453 if (reportErrors) {
21428- const errorNode = getCallErrorNode(node);
21429- diagnostics.add(createDiagnosticForNode(errorNode, Diagnostics.Call_target_does_not_contain_any_signatures));
21454+ diagnostics.add(getDiagnosticForCallNode(node, Diagnostics.Call_target_does_not_contain_any_signatures));
2143021455 }
2143121456 return resolveErrorCall(node);
2143221457 }
@@ -21504,45 +21529,32 @@ namespace ts {
2150421529 // If candidate is undefined, it means that no candidates had a suitable arity. In that case,
2150521530 // skip the checkApplicableSignature check.
2150621531 if (reportErrors) {
21507- const errorNode = getCallErrorNode(node);
2150821532
2150921533 if (candidateForArgumentError) {
2151021534 checkApplicableSignature(node, args, candidateForArgumentError, assignableRelation, CheckMode.Normal, /*reportErrors*/ true);
2151121535 }
2151221536 else if (candidateForArgumentArityError) {
21513- diagnostics.add(getArgumentArityError(errorNode , [candidateForArgumentArityError], args));
21537+ diagnostics.add(getArgumentArityError(node , [candidateForArgumentArityError], args));
2151421538 }
2151521539 else if (candidateForTypeArgumentError) {
2151621540 checkTypeArguments(candidateForTypeArgumentError, (node as CallExpression | TaggedTemplateExpression | JsxOpeningLikeElement).typeArguments!, /*reportErrors*/ true, fallbackError);
2151721541 }
2151821542 else {
2151921543 const signaturesWithCorrectTypeArgumentArity = filter(signatures, s => hasCorrectTypeArgumentArity(s, typeArguments));
2152021544 if (signaturesWithCorrectTypeArgumentArity.length === 0) {
21521- diagnostics.add(getTypeArgumentArityError(errorNode , signatures, typeArguments!));
21545+ diagnostics.add(getTypeArgumentArityError(node , signatures, typeArguments!));
2152221546 }
2152321547 else if (!isDecorator) {
21524- diagnostics.add(getArgumentArityError(errorNode , signaturesWithCorrectTypeArgumentArity, args));
21548+ diagnostics.add(getArgumentArityError(node , signaturesWithCorrectTypeArgumentArity, args));
2152521549 }
2152621550 else if (fallbackError) {
21527- diagnostics.add(createDiagnosticForNode(errorNode , fallbackError));
21551+ diagnostics.add(getDiagnosticForCallNode(node , fallbackError));
2152821552 }
2152921553 }
2153021554 }
2153121555
2153221556 return produceDiagnostics || !args ? resolveErrorCall(node) : getCandidateForOverloadFailure(node, candidates, args, !!candidatesOutArray);
2153321557
21534- function getCallErrorNode(node: CallLikeExpression): Node {
21535- if (isCallExpression(node)) {
21536- if (isPropertyAccessExpression(node.expression)) {
21537- return node.expression.name;
21538- }
21539- else {
21540- return node.expression;
21541- }
21542- }
21543- return node;
21544- }
21545-
2154621558 function chooseOverload(candidates: Signature[], relation: Map<RelationComparisonResult>, signatureHelpTrailingComma = false) {
2154721559 candidateForArgumentError = undefined;
2154821560 candidateForArgumentArityError = undefined;
@@ -21825,7 +21837,7 @@ namespace ts {
2182521837 relatedInformation = createDiagnosticForNode(node.expression, Diagnostics.It_is_highly_likely_that_you_are_missing_a_semicolon);
2182621838 }
2182721839 }
21828- invocationError(node, apparentType, SignatureKind.Call, relatedInformation);
21840+ invocationError(node.expression , apparentType, SignatureKind.Call, relatedInformation);
2182921841 }
2183021842 return resolveErrorCall(node);
2183121843 }
@@ -21942,7 +21954,7 @@ namespace ts {
2194221954 return signature;
2194321955 }
2194421956
21945- invocationError(node, expressionType, SignatureKind.Construct);
21957+ invocationError(node.expression , expressionType, SignatureKind.Construct);
2194621958 return resolveErrorCall(node);
2194721959 }
2194821960
@@ -22015,11 +22027,88 @@ namespace ts {
2201522027 return true;
2201622028 }
2201722029
22018- function invocationError(node: Node, apparentType: Type, kind: SignatureKind, relatedInformation?: DiagnosticRelatedInformation) {
22019- const diagnostic = error(node, (kind === SignatureKind.Call ?
22020- Diagnostics.Cannot_invoke_an_expression_whose_type_lacks_a_call_signature_Type_0_has_no_compatible_call_signatures :
22021- Diagnostics.Cannot_use_new_with_an_expression_whose_type_lacks_a_call_or_construct_signature
22022- ), typeToString(apparentType));
22030+ function invocationErrorDetails(apparentType: Type, kind: SignatureKind): DiagnosticMessageChain {
22031+ let errorInfo: DiagnosticMessageChain | undefined;
22032+ const isCall = kind === SignatureKind.Call;
22033+ if (apparentType.flags & TypeFlags.Union) {
22034+ const types = (apparentType as UnionType).types;
22035+ let hasSignatures = false;
22036+ for (const constituent of types) {
22037+ const signatures = getSignaturesOfType(constituent, kind);
22038+ if (signatures.length !== 0) {
22039+ hasSignatures = true;
22040+ if (errorInfo) {
22041+ // Bail early if we already have an error, no chance of "No constituent of type is callable"
22042+ break;
22043+ }
22044+ }
22045+ else {
22046+ // Error on the first non callable constituent only
22047+ if (!errorInfo) {
22048+ errorInfo = chainDiagnosticMessages(
22049+ errorInfo,
22050+ isCall ?
22051+ Diagnostics.Type_0_has_no_call_signatures :
22052+ Diagnostics.Type_0_has_no_construct_signatures,
22053+ typeToString(constituent)
22054+ );
22055+ errorInfo = chainDiagnosticMessages(
22056+ errorInfo,
22057+ isCall ?
22058+ Diagnostics.Not_all_constituents_of_type_0_are_callable :
22059+ Diagnostics.Not_all_constituents_of_type_0_are_constructable,
22060+ typeToString(apparentType)
22061+ );
22062+ }
22063+ if (hasSignatures) {
22064+ // Bail early if we already found a siganture, no chance of "No constituent of type is callable"
22065+ break;
22066+ }
22067+ }
22068+ }
22069+ if (!hasSignatures) {
22070+ errorInfo = chainDiagnosticMessages(
22071+ /* detials */ undefined,
22072+ isCall ?
22073+ Diagnostics.No_constituent_of_type_0_is_callable :
22074+ Diagnostics.No_constituent_of_type_0_is_constructable,
22075+ typeToString(apparentType)
22076+ );
22077+ }
22078+ if (!errorInfo) {
22079+ errorInfo = chainDiagnosticMessages(
22080+ errorInfo,
22081+ isCall ?
22082+ Diagnostics.Each_member_of_the_union_type_0_has_signatures_but_none_of_those_signatures_are_compatible_with_each_other :
22083+ Diagnostics.Each_member_of_the_union_type_0_has_construct_signatures_but_none_of_those_signatures_are_compatible_with_each_other,
22084+ typeToString(apparentType)
22085+ );
22086+ }
22087+ }
22088+ else {
22089+ errorInfo = chainDiagnosticMessages(
22090+ errorInfo,
22091+ isCall ?
22092+ Diagnostics.Type_0_has_no_call_signatures :
22093+ Diagnostics.Type_0_has_no_construct_signatures,
22094+ typeToString(apparentType)
22095+ );
22096+ }
22097+ return chainDiagnosticMessages(
22098+ errorInfo,
22099+ isCall ?
22100+ Diagnostics.This_expression_is_not_callable :
22101+ Diagnostics.This_expression_is_not_constructable
22102+ );
22103+ }
22104+ function invocationError(errorTarget: Node, apparentType: Type, kind: SignatureKind, relatedInformation?: DiagnosticRelatedInformation) {
22105+ const diagnostic = createDiagnosticForNodeFromMessageChain(errorTarget, invocationErrorDetails(apparentType, kind));
22106+ if (isCallExpression(errorTarget.parent)) {
22107+ const { start, length } = getDiagnosticSpanForCallNode(errorTarget.parent, /* doNotIncludeArguments */ true);
22108+ diagnostic.start = start;
22109+ diagnostic.length = length;
22110+ }
22111+ diagnostics.add(diagnostic);
2202322112 invocationErrorRecovery(apparentType, kind, relatedInformation ? addRelatedInfo(diagnostic, relatedInformation) : diagnostic);
2202422113 }
2202522114
@@ -22057,7 +22146,7 @@ namespace ts {
2205722146 }
2205822147
2205922148 if (!callSignatures.length) {
22060- invocationError(node, apparentType, SignatureKind.Call);
22149+ invocationError(node.tag , apparentType, SignatureKind.Call);
2206122150 return resolveErrorCall(node);
2206222151 }
2206322152
@@ -22113,9 +22202,9 @@ namespace ts {
2211322202
2211422203 const headMessage = getDiagnosticHeadMessageForDecoratorResolution(node);
2211522204 if (!callSignatures.length) {
22116- 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) );
22205+ let errorInfo = invocationErrorDetails(apparentType, SignatureKind.Call );
2211722206 errorInfo = chainDiagnosticMessages(errorInfo, headMessage);
22118- const diag = createDiagnosticForNodeFromMessageChain(node, errorInfo);
22207+ const diag = createDiagnosticForNodeFromMessageChain(node.expression , errorInfo);
2211922208 diagnostics.add(diag);
2212022209 invocationErrorRecovery(apparentType, SignatureKind.Call, diag);
2212122210 return resolveErrorCall(node);
0 commit comments