Use existing reporting mechanism

This commit is contained in:
Nathan Shively-Sanders 2019-06-24 15:32:58 -07:00
parent 720ad5bf22
commit ecfa902ba1
3 changed files with 198 additions and 102 deletions

View File

@ -11668,52 +11668,76 @@ namespace ts {
* attempt to issue more specific errors on, for example, specific object literal properties or tuple members.
*/
function checkTypeAssignableToAndOptionallyElaborate(source: Type, target: Type, errorNode: Node | undefined, expr: Expression | undefined, headMessage?: DiagnosticMessage, containingMessageChain?: () => DiagnosticMessageChain | undefined): boolean {
return checkTypeRelatedToAndOptionallyElaborate(source, target, assignableRelation, errorNode, expr, headMessage, containingMessageChain);
return checkTypeRelatedToAndOptionallyElaborate(source, target, assignableRelation, errorNode, expr, headMessage, containingMessageChain, /*errorOutputContainer*/ undefined);
}
function checkTypeRelatedToAndOptionallyElaborate(source: Type, target: Type, relation: Map<RelationComparisonResult>, errorNode: Node | undefined, expr: Expression | undefined, headMessage?: DiagnosticMessage, containingMessageChain?: () => DiagnosticMessageChain | undefined): boolean;
function checkTypeRelatedToAndOptionallyElaborate(source: Type, target: Type, relation: Map<RelationComparisonResult>, errorNode: Node | undefined, expr: Expression | undefined, headMessage?: DiagnosticMessage, containingMessageChain?: () => DiagnosticMessageChain | undefined, breakdown?: boolean): [Node, DiagnosticMessageChain, DiagnosticRelatedInformation[]?] | false;
function checkTypeRelatedToAndOptionallyElaborate(source: Type, target: Type, relation: Map<RelationComparisonResult>, errorNode: Node | undefined, expr: Expression | undefined, headMessage?: DiagnosticMessage, containingMessageChain?: () => DiagnosticMessageChain | undefined, breakdown?: boolean): boolean | [Node, DiagnosticMessageChain, DiagnosticRelatedInformation[]?] {
if (isTypeRelatedTo(source, target, relation)) return breakdown ? false : true;
if (!errorNode || !elaborateError(expr, source, target, relation, headMessage)) {
return checkTypeRelatedTo(source, target, relation, errorNode, headMessage, containingMessageChain, undefined, breakdown);
function checkTypeRelatedToAndOptionallyElaborate(
source: Type,
target: Type,
relation: Map<RelationComparisonResult>,
errorNode: Node | undefined,
expr: Expression | undefined,
headMessage: DiagnosticMessage | undefined,
containingMessageChain: (() => DiagnosticMessageChain | undefined) | undefined,
errorOutputContainer: { error?: Diagnostic, skipLogging?: boolean } | undefined
): boolean {
if (isTypeRelatedTo(source, target, relation)) return true;
if (!errorNode || !elaborateError(expr, source, target, relation, headMessage, errorOutputContainer)) {
return checkTypeRelatedTo(source, target, relation, errorNode, headMessage, containingMessageChain, errorOutputContainer);
}
return breakdown ? [undefined!,undefined!] as [Node, DiagnosticMessageChain] : false;
return false;
}
function isOrHasGenericConditional(type: Type): boolean {
return !!(type.flags & TypeFlags.Conditional || (type.flags & TypeFlags.Intersection && some((type as IntersectionType).types, isOrHasGenericConditional)));
}
function elaborateError(node: Expression | undefined, source: Type, target: Type, relation: Map<RelationComparisonResult>, headMessage: DiagnosticMessage | undefined): boolean {
function elaborateError(
node: Expression | undefined,
source: Type,
target: Type,
relation: Map<RelationComparisonResult>,
headMessage: DiagnosticMessage | undefined,
errorOutputContainer: { error?: Diagnostic, skipLogging?: boolean } | undefined
): boolean {
// TODO: The first case probably still needs to set errorOutputContainer.error to something
// TODO: Make sure all error logging in dynamic scope sets errorOutputContainer.error instead
if (!node || isOrHasGenericConditional(target)) return false;
if (!checkTypeRelatedTo(source, target, relation, /*errorNode*/ undefined) && elaborateDidYouMeanToCallOrConstruct(node, source, target, relation, headMessage)) {
if (!checkTypeRelatedTo(source, target, relation, /*errorNode*/ undefined)
&& elaborateDidYouMeanToCallOrConstruct(node, source, target, relation, headMessage, errorOutputContainer)) {
return true;
}
switch (node.kind) {
case SyntaxKind.JsxExpression:
case SyntaxKind.ParenthesizedExpression:
return elaborateError((node as ParenthesizedExpression | JsxExpression).expression, source, target, relation, headMessage);
return elaborateError((node as ParenthesizedExpression | JsxExpression).expression, source, target, relation, headMessage, errorOutputContainer);
case SyntaxKind.BinaryExpression:
switch ((node as BinaryExpression).operatorToken.kind) {
case SyntaxKind.EqualsToken:
case SyntaxKind.CommaToken:
return elaborateError((node as BinaryExpression).right, source, target, relation, headMessage);
return elaborateError((node as BinaryExpression).right, source, target, relation, headMessage, errorOutputContainer);
}
break;
case SyntaxKind.ObjectLiteralExpression:
return elaborateObjectLiteral(node as ObjectLiteralExpression, source, target, relation);
return elaborateObjectLiteral(node as ObjectLiteralExpression, source, target, relation, errorOutputContainer);
case SyntaxKind.ArrayLiteralExpression:
return elaborateArrayLiteral(node as ArrayLiteralExpression, source, target, relation);
return elaborateArrayLiteral(node as ArrayLiteralExpression, source, target, relation, errorOutputContainer);
case SyntaxKind.JsxAttributes:
return elaborateJsxComponents(node as JsxAttributes, source, target, relation);
return elaborateJsxComponents(node as JsxAttributes, source, target, relation, errorOutputContainer);
case SyntaxKind.ArrowFunction:
return elaborateArrowFunction(node as ArrowFunction, source, target, relation);
return elaborateArrowFunction(node as ArrowFunction, source, target, relation, errorOutputContainer);
}
return false;
}
function elaborateDidYouMeanToCallOrConstruct(node: Expression, source: Type, target: Type, relation: Map<RelationComparisonResult>, headMessage: DiagnosticMessage | undefined): boolean {
function elaborateDidYouMeanToCallOrConstruct(
node: Expression,
source: Type,
target: Type,
relation: Map<RelationComparisonResult>,
headMessage: DiagnosticMessage | undefined,
errorOutputContainer: { error?: Diagnostic, skipLogging?: boolean } | undefined
): boolean {
const callSignatures = getSignaturesOfType(source, SignatureKind.Call);
const constructSignatures = getSignaturesOfType(source, SignatureKind.Construct);
for (const signatures of [constructSignatures, callSignatures]) {
@ -11721,7 +11745,7 @@ namespace ts {
const returnType = getReturnTypeOfSignature(s);
return !(returnType.flags & (TypeFlags.Any | TypeFlags.Never)) && checkTypeRelatedTo(returnType, target, relation, /*errorNode*/ undefined);
})) {
const resultObj: { error?: Diagnostic } = {};
const resultObj: { error?: Diagnostic } = errorOutputContainer || {};
checkTypeAssignableTo(source, target, node, headMessage, /*containingChain*/ undefined, resultObj);
const diagnostic = resultObj.error!;
addRelatedInfo(diagnostic, createDiagnosticForNode(
@ -11734,7 +11758,13 @@ namespace ts {
return false;
}
function elaborateArrowFunction(node: ArrowFunction, source: Type, target: Type, relation: Map<RelationComparisonResult>): boolean {
function elaborateArrowFunction(
node: ArrowFunction,
source: Type,
target: Type,
relation: Map<RelationComparisonResult>,
errorOutputContainer: { error?: Diagnostic, skipLogging?: boolean } | undefined
): boolean {
// Don't elaborate blocks
if (isBlock(node.body)) {
return false;
@ -11755,11 +11785,11 @@ namespace ts {
const sourceReturn = getReturnTypeOfSignature(sourceSig);
const targetReturn = getUnionType(map(targetSignatures, getReturnTypeOfSignature));
if (!checkTypeRelatedTo(sourceReturn, targetReturn, relation, /*errorNode*/ undefined)) {
const elaborated = returnExpression && elaborateError(returnExpression, sourceReturn, targetReturn, relation, /*headMessage*/ undefined);
const elaborated = returnExpression && elaborateError(returnExpression, sourceReturn, targetReturn, relation, /*headMessage*/ undefined, errorOutputContainer);
if (elaborated) {
return elaborated;
}
const resultObj: { error?: Diagnostic } = {};
const resultObj: { error?: Diagnostic } = errorOutputContainer || {};
checkTypeRelatedTo(sourceReturn, targetReturn, relation, returnExpression, /*message*/ undefined, /*chain*/ undefined, resultObj);
if (resultObj.error) {
if (target.symbol && length(target.symbol.declarations)) {
@ -11780,7 +11810,13 @@ namespace ts {
* If that element would issue an error, we first attempt to dive into that element's inner expression and issue a more specific error by recuring into `elaborateError`
* Otherwise, we issue an error on _every_ element which fail the assignability check
*/
function elaborateElementwise(iterator: ElaborationIterator, source: Type, target: Type, relation: Map<RelationComparisonResult>) {
function elaborateElementwise(
iterator: ElaborationIterator,
source: Type,
target: Type,
relation: Map<RelationComparisonResult>,
errorOutputContainer: { error?: Diagnostic, skipLogging?: boolean } | undefined
) {
// Assignability failure - check each prop individually, and if that fails, fall back on the bad error span
let reportedError = false;
for (let status = iterator.next(); !status.done; status = iterator.next()) {
@ -11789,13 +11825,13 @@ namespace ts {
if (!targetPropType || targetPropType.flags & TypeFlags.IndexedAccess) continue; // Don't elaborate on indexes on generic variables
const sourcePropType = getIndexedAccessTypeOrUndefined(source, nameType);
if (sourcePropType && !checkTypeRelatedTo(sourcePropType, targetPropType, relation, /*errorNode*/ undefined)) {
const elaborated = next && elaborateError(next, sourcePropType, targetPropType, relation, /*headMessage*/ undefined);
const elaborated = next && elaborateError(next, sourcePropType, targetPropType, relation, /*headMessage*/ undefined, errorOutputContainer);
if (elaborated) {
reportedError = true;
}
else {
// Issue error on the prop itself, since the prop couldn't elaborate the error
const resultObj: { error?: Diagnostic } = {};
const resultObj: { error?: Diagnostic } = errorOutputContainer || {};
// Use the expression type, if available
const specificSource = next ? checkExpressionForMutableLocation(next, CheckMode.Normal, sourcePropType) : sourcePropType;
const result = checkTypeRelatedTo(specificSource, targetPropType, relation, prop, errorMessage, /*containingChain*/ undefined, resultObj);
@ -11887,8 +11923,14 @@ namespace ts {
return filter(children, i => !isJsxText(i) || !i.containsOnlyTriviaWhiteSpaces);
}
function elaborateJsxComponents(node: JsxAttributes, source: Type, target: Type, relation: Map<RelationComparisonResult>) {
let result = elaborateElementwise(generateJsxAttributes(node), source, target, relation);
function elaborateJsxComponents(
node: JsxAttributes,
source: Type,
target: Type,
relation: Map<RelationComparisonResult>,
errorOutputContainer: { error?: Diagnostic, skipLogging?: boolean } | undefined
) {
let result = elaborateElementwise(generateJsxAttributes(node), source, target, relation, errorOutputContainer);
let invalidTextDiagnostic: DiagnosticMessage | undefined;
if (isJsxOpeningElement(node.parent) && isJsxElement(node.parent.parent)) {
const containingElement = node.parent.parent;
@ -11906,17 +11948,21 @@ namespace ts {
if (moreThanOneRealChildren) {
if (arrayLikeTargetParts !== neverType) {
const realSource = createTupleType(checkJsxChildren(containingElement, CheckMode.Normal));
result = elaborateElementwise(generateJsxChildren(containingElement, getInvalidTextualChildDiagnostic), realSource, arrayLikeTargetParts, relation) || result;
const children = generateJsxChildren(containingElement, getInvalidTextualChildDiagnostic)
result = elaborateElementwise(children, realSource, arrayLikeTargetParts, relation, errorOutputContainer) || result;
}
else if (!isTypeRelatedTo(getIndexedAccessType(source, childrenNameType), childrenTargetType, relation)) {
// arity mismatch
result = true;
error(
const diag = error(
containingElement.openingElement.tagName,
Diagnostics.This_JSX_tag_s_0_prop_expects_a_single_child_of_type_1_but_multiple_children_were_provided,
childrenPropName,
typeToString(childrenTargetType)
);
if (errorOutputContainer && errorOutputContainer.skipLogging) {
errorOutputContainer.error = diag;
}
}
}
else {
@ -11928,19 +11974,23 @@ namespace ts {
(function*() { yield elem; })(),
source,
target,
relation
relation,
errorOutputContainer
) || result;
}
}
else if (!isTypeRelatedTo(getIndexedAccessType(source, childrenNameType), childrenTargetType, relation)) {
// arity mismatch
result = true;
error(
const diag = error(
containingElement.openingElement.tagName,
Diagnostics.This_JSX_tag_s_0_prop_expects_type_1_which_requires_multiple_children_but_only_a_single_child_was_provided,
childrenPropName,
typeToString(childrenTargetType)
);
if (errorOutputContainer && errorOutputContainer.skipLogging) {
errorOutputContainer.error = diag;
}
}
}
}
@ -11972,15 +12022,21 @@ namespace ts {
}
}
function elaborateArrayLiteral(node: ArrayLiteralExpression, source: Type, target: Type, relation: Map<RelationComparisonResult>) {
function elaborateArrayLiteral(
node: ArrayLiteralExpression,
source: Type,
target: Type,
relation: Map<RelationComparisonResult>,
errorOutputContainer: { error?: Diagnostic, skipLogging?: boolean } | undefined
) {
if (target.flags & TypeFlags.Primitive) return false;
if (isTupleLikeType(source)) {
return elaborateElementwise(generateLimitedTupleElements(node, target), source, target, relation);
return elaborateElementwise(generateLimitedTupleElements(node, target), source, target, relation, errorOutputContainer);
}
// recreate a tuple from the elements, if possible
const tupleizedType = checkArrayLiteral(node, CheckMode.Contextual, /*forceTuple*/ true);
if (isTupleLikeType(tupleizedType)) {
return elaborateElementwise(generateLimitedTupleElements(node, target), tupleizedType, target, relation);
return elaborateElementwise(generateLimitedTupleElements(node, target), tupleizedType, target, relation, errorOutputContainer);
}
return false;
}
@ -12009,9 +12065,15 @@ namespace ts {
}
}
function elaborateObjectLiteral(node: ObjectLiteralExpression, source: Type, target: Type, relation: Map<RelationComparisonResult>) {
function elaborateObjectLiteral(
node: ObjectLiteralExpression,
source: Type,
target: Type,
relation: Map<RelationComparisonResult>,
errorOutputContainer: { error?: Diagnostic, skipLogging?: boolean } | undefined
) {
if (target.flags & TypeFlags.Primitive) return false;
return elaborateElementwise(generateObjectLiteralElements(node), source, target, relation);
return elaborateElementwise(generateObjectLiteralElements(node), source, target, relation, errorOutputContainer);
}
/**
@ -12343,25 +12405,6 @@ namespace ts {
return getObjectFlags(source) & ObjectFlags.JsxAttributes && !isUnhyphenatedJsxName(sourceProp.escapedName);
}
function checkTypeRelatedTo(
source: Type,
target: Type,
relation: Map<RelationComparisonResult>,
errorNode: Node | undefined,
headMessage?: DiagnosticMessage,
containingMessageChain?: () => DiagnosticMessageChain | undefined,
errorOutputContainer?: { error?: Diagnostic },
): boolean;
function checkTypeRelatedTo(
source: Type,
target: Type,
relation: Map<RelationComparisonResult>,
errorNode: Node | undefined,
headMessage?: DiagnosticMessage,
containingMessageChain?: () => DiagnosticMessageChain | undefined,
errorOutputContainer?: { error?: Diagnostic },
breakdown?: boolean
): false | [Node, DiagnosticMessageChain, DiagnosticRelatedInformation[]?];
/**
* Checks if 'source' is related to 'target' (e.g.: is a assignable to).
* @param source The left-hand-side of the relation.
@ -12371,6 +12414,7 @@ namespace ts {
* @param errorNode The suggested node upon which all errors will be reported, if defined. This may or may not be the actual node used.
* @param headMessage If the error chain should be prepended by a head message, then headMessage will be used.
* @param containingMessageChain A chain of errors to prepend any new errors found.
* @param errorOutputContainer Return the diagnostic. Do not log if 'skipLogging' is truthy.
*/
function checkTypeRelatedTo(
source: Type,
@ -12379,9 +12423,8 @@ namespace ts {
errorNode: Node | undefined,
headMessage?: DiagnosticMessage,
containingMessageChain?: () => DiagnosticMessageChain | undefined,
errorOutputContainer?: { error?: Diagnostic },
breakdown?: boolean
): boolean | [Node, DiagnosticMessageChain, DiagnosticRelatedInformation[]?] {
errorOutputContainer?: { error?: Diagnostic, skipLogging?: boolean },
): boolean {
let errorInfo: DiagnosticMessageChain | undefined;
let relatedInfo: [DiagnosticRelatedInformation, ...DiagnosticRelatedInformation[]] | undefined;
let maybeKeys: string[];
@ -12397,7 +12440,10 @@ namespace ts {
const result = isRelatedTo(source, target, /*reportErrors*/ !!errorNode, headMessage);
if (overflow) {
error(errorNode, Diagnostics.Excessive_stack_depth_comparing_types_0_and_1, typeToString(source), typeToString(target));
const diag = error(errorNode, Diagnostics.Excessive_stack_depth_comparing_types_0_and_1, typeToString(source), typeToString(target));
if (errorOutputContainer) {
errorOutputContainer.error = diag;
}
}
else if (errorInfo) {
if (containingMessageChain) {
@ -12420,9 +12466,6 @@ namespace ts {
}
}
}
if (breakdown) {
return [errorNode!, errorInfo, relatedInfo ? [...(relatedInformation || []), ...relatedInfo]: relatedInformation];
}
const diag = createDiagnosticForNodeFromMessageChain(errorNode!, errorInfo, relatedInformation);
if (relatedInfo) {
addRelatedInfo(diag, ...relatedInfo);
@ -12430,11 +12473,12 @@ namespace ts {
if (errorOutputContainer) {
errorOutputContainer.error = diag;
}
diagnostics.add(diag); // TODO: GH#18217
if (!errorOutputContainer || !errorOutputContainer.skipLogging) {
diagnostics.add(diag);
}
}
if (breakdown) {
Debug.assert(result === Ternary.False ? !errorNode : true, "missed opportunity to interact with error.");
return result === Ternary.False ? [undefined!, undefined!] as [Node, DiagnosticMessageChain] : false;
if (errorNode && errorOutputContainer && errorOutputContainer.skipLogging && result === Ternary.False) {
Debug.assert(!!errorOutputContainer.error, "missed opportunity to interact with error.");
}
return result !== Ternary.False;
@ -21127,13 +21171,14 @@ namespace ts {
checkMode: CheckMode,
reportErrors: boolean,
containingMessageChain: (() => DiagnosticMessageChain | undefined) | undefined,
errorOutputContainer: { error?: Diagnostic, skipLogging?: boolean }
) {
// Stateless function components can have maximum of three arguments: "props", "context", and "updater".
// However "context" and "updater" are implicit and can't be specify by users. Only the first parameter, props,
// can be specified by users through attributes property.
const paramType = getEffectiveFirstArgumentForJsxSignature(signature, node);
const attributesType = checkExpressionWithContextualType(node.attributes, paramType, /*inferenceContext*/ undefined, checkMode);
return checkTypeRelatedToAndOptionallyElaborate(attributesType, paramType, relation, reportErrors ? node.tagName : undefined, node.attributes, undefined, containingMessageChain, /*breakdown*/ true);
return checkTypeRelatedToAndOptionallyElaborate(attributesType, paramType, relation, reportErrors ? node.tagName : undefined, node.attributes, undefined, containingMessageChain, errorOutputContainer);
}
function getSignatureApplicabilityError(
@ -21145,8 +21190,19 @@ namespace ts {
reportErrors: boolean,
containingMessageChain: (() => DiagnosticMessageChain | undefined) | undefined,
) {
const errorOutputContainer: { error?: Diagnostic, skipLogging?: boolean } = { error: undefined, skipLogging: true };
if (isJsxOpeningLikeElement(node)) {
return checkApplicableSignatureForJsxOpeningLikeElement(node, signature, relation, checkMode, reportErrors, containingMessageChain);
const r = checkApplicableSignatureForJsxOpeningLikeElement(node, signature, relation, checkMode, reportErrors, containingMessageChain, errorOutputContainer);
if (!r) {
if (reportErrors) {
Debug.assert(!!errorOutputContainer.error, "has error 0");
return errorOutputContainer.error;
}
else {
return true;
}
}
}
const thisType = getThisTypeOfSignature(signature);
if (thisType && thisType !== voidType && node.kind !== SyntaxKind.NewExpression) {
@ -21157,9 +21213,15 @@ namespace ts {
const thisArgumentType = thisArgumentNode ? checkExpression(thisArgumentNode) : voidType;
const errorNode = reportErrors ? (thisArgumentNode || node) : undefined;
const headMessage = Diagnostics.The_this_context_of_type_0_is_not_assignable_to_method_s_this_of_type_1;
const r = checkTypeRelatedTo(thisArgumentType, thisType, relation, errorNode, headMessage, containingMessageChain, undefined, /*breakdown*/ true);
if (r) {
return r;
const r = checkTypeRelatedTo(thisArgumentType, thisType, relation, errorNode, headMessage, containingMessageChain, errorOutputContainer);
if (!r) {
if (reportErrors) {
Debug.assert(!!errorOutputContainer.error, "has error 1"); // CLEAR
return errorOutputContainer.error;
}
else {
return true;
}
}
}
const headMessage = Diagnostics.Argument_of_type_0_is_not_assignable_to_parameter_of_type_1;
@ -21174,16 +21236,31 @@ namespace ts {
// we obtain the regular type of any object literal arguments because we may not have inferred complete
// parameter types yet and therefore excess property checks may yield false positives (see #17041).
const checkArgType = checkMode & CheckMode.SkipContextSensitive ? getRegularTypeOfObjectLiteral(argType) : argType;
const r = checkTypeRelatedToAndOptionallyElaborate(checkArgType, paramType, relation, reportErrors ? arg : undefined, arg, headMessage, containingMessageChain, /*breakdown*/ true);
if (r) {
return r;
const r = checkTypeRelatedToAndOptionallyElaborate(checkArgType, paramType, relation, reportErrors ? arg : undefined, arg, headMessage, containingMessageChain, errorOutputContainer);
if (!r) {
if (reportErrors) {
Debug.assert(!!errorOutputContainer.error, "has error 2"); // CLEAR
return errorOutputContainer.error;
}
else {
return true;
}
}
}
}
if (restType) {
const spreadType = getSpreadArgumentType(args, argCount, args.length, restType, /*context*/ undefined);
const errorNode = reportErrors ? argCount < args.length ? args[argCount] : node : undefined;
return checkTypeRelatedTo(spreadType, restType, relation, errorNode, headMessage, undefined, undefined, /*breakdown*/ true);
const r = checkTypeRelatedTo(spreadType, restType, relation, errorNode, headMessage, undefined, errorOutputContainer);
if (!r) {
if (reportErrors) {
Debug.assert(!!errorOutputContainer.error, "has error 3"); // CLEAR
return errorOutputContainer.error;
}
else {
return true;
}
}
}
return undefined;
}
@ -21520,10 +21597,13 @@ namespace ts {
chain = chainDiagnosticMessages(chain, Diagnostics.The_last_overload_gave_the_following_error);
chain = chainDiagnosticMessages(chain, Diagnostics.No_suitable_overload_for_this_call);
}
const r = getSignatureApplicabilityError(node, args, last, assignableRelation, CheckMode.Normal, /*reportErrors*/ true, () => chain);
Debug.assert(!!r && !!r[0], "No error for last signature");
if (r) {
diagnostics.add(createDiagnosticForNodeFromMessageChain(...r));
const d = getSignatureApplicabilityError(node, args, last, assignableRelation, CheckMode.Normal, /*reportErrors*/ true, () => chain);
Debug.assert(!!d, "No error for last signature");
if (d) {
Debug.assert(d !== true);
// if elaboration already displayed the error, don't do anything extra
// note that we could do this always here, but getSignatureApplicabilityError is currently not configured to do that
diagnostics.add(d as Diagnostic);
}
}
else {
@ -21532,10 +21612,11 @@ namespace ts {
for (const c of candidatesForArgumentError) {
i++;
const chain = chainDiagnosticMessages(undefined, Diagnostics.Overload_0_of_1_2_gave_the_following_error, i, candidates.length, signatureToString(c));
const r = getSignatureApplicabilityError(node, args, c, assignableRelation, CheckMode.Normal, /*reportErrors*/ true, () => chain);
Debug.assert(!!r && !!r[0], "No error for signature (1)");
if (r) {
related.push(createDiagnosticForNodeFromMessageChain(...r));
const d = getSignatureApplicabilityError(node, args, c, assignableRelation, CheckMode.Normal, /*reportErrors*/ true, () => chain);
Debug.assert(!!d, "No error for signature (1)");
if (d) {
Debug.assert(d !== true);
related.push(d as Diagnostic);
}
}
diagnostics.add(createDiagnosticForNodeFromMessageChain(node, chainDiagnosticMessages(undefined, Diagnostics.No_suitable_overload_for_this_call), related));

View File

@ -1,8 +1,7 @@
tests/cases/conformance/jsx/file.tsx(48,13): error TS2322: Type '{ children: string; to: string; onClick: (e: any) => void; }' is not assignable to type 'IntrinsicAttributes & HyphenProps'.
Property 'to' does not exist on type 'IntrinsicAttributes & HyphenProps'.
tests/cases/conformance/jsx/file.tsx(54,51): error TS2322: Type 'number' is not assignable to type 'string'.
tests/cases/conformance/jsx/file.tsx(55,68): error TS2322: Type 'true' is not assignable to type 'string'.
tests/cases/conformance/jsx/file.tsx(56,24): error TS2322: Type 'true' is not assignable to type 'string'.
tests/cases/conformance/jsx/file.tsx(48,12): error TS2755: No suitable overload for this call.
tests/cases/conformance/jsx/file.tsx(54,12): error TS2755: No suitable overload for this call.
tests/cases/conformance/jsx/file.tsx(55,12): error TS2755: No suitable overload for this call.
tests/cases/conformance/jsx/file.tsx(56,12): error TS2755: No suitable overload for this call.
==== tests/cases/conformance/jsx/file.tsx (4 errors) ====
@ -54,23 +53,39 @@ tests/cases/conformance/jsx/file.tsx(56,24): error TS2322: Type 'true' is not as
// Error
const b0 = <MainButton to='/some/path' onClick={(e)=>{}}>GO</MainButton>; // extra property;
~~~~~~~~~~
!!! error TS2322: Type '{ children: string; to: string; onClick: (e: any) => void; }' is not assignable to type 'IntrinsicAttributes & HyphenProps'.
!!! error TS2322: Property 'to' does not exist on type 'IntrinsicAttributes & HyphenProps'.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2755: No suitable overload for this call.
!!! related TS2757 tests/cases/conformance/jsx/file.tsx:48:13: Overload 1 of 3, '(buttonProps: ButtonProps): Element', gave the following error.
Type '{ children: string; to: string; onClick: (e: MouseEvent<any>) => void; }' is not assignable to type 'IntrinsicAttributes & ButtonProps'.
Property 'to' does not exist on type 'IntrinsicAttributes & ButtonProps'.
!!! related TS2757 tests/cases/conformance/jsx/file.tsx:48:13: Overload 2 of 3, '(linkProps: LinkProps): Element', gave the following error.
Type '{ children: string; to: string; onClick: (e: MouseEvent<any>) => void; }' is not assignable to type 'IntrinsicAttributes & LinkProps'.
Property 'onClick' does not exist on type 'IntrinsicAttributes & LinkProps'.
!!! related TS2757 tests/cases/conformance/jsx/file.tsx:48:13: Overload 3 of 3, '(hyphenProps: HyphenProps): Element', gave the following error.
Type '{ children: string; to: string; onClick: (e: MouseEvent<any>) => void; }' is not assignable to type 'IntrinsicAttributes & HyphenProps'.
Property 'to' does not exist on type 'IntrinsicAttributes & HyphenProps'.
const b1 = <MainButton onClick={(e: any)=> {}} {...obj0}>Hello world</MainButton>; // extra property;
const b2 = <MainButton {...{to: "10000"}} {...obj2} />; // extra property
const b3 = <MainButton {...{to: "10000"}} {...{onClick: (k) => {}}} />; // extra property
const b4 = <MainButton {...obj3} to />; // Should error because Incorrect type; but attributes are any so everything is allowed
const b5 = <MainButton {...{ onClick(e: any) { } }} {...obj0} />; // Spread retain method declaration (see GitHub #13365), so now there is an extra attributes
const b6 = <MainButton {...{ onClick(e: any){} }} children={10} />; // incorrect type for optional attribute
~~~~~~~~
!!! error TS2322: Type 'number' is not assignable to type 'string'.
!!! related TS6500 tests/cases/conformance/jsx/file.tsx:4:5: The expected type comes from property 'children' which is declared here on type 'IntrinsicAttributes & HyphenProps'
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2755: No suitable overload for this call.
!!! related TS2322 tests/cases/conformance/jsx/file.tsx:54:51: Type 'number' is not assignable to type 'string'.
!!! related TS2322 tests/cases/conformance/jsx/file.tsx:54:51: Type 'number' is not assignable to type 'string'.
!!! related TS2322 tests/cases/conformance/jsx/file.tsx:54:51: Type 'number' is not assignable to type 'string'.
const b7 = <MainButton {...{ onClick(e: any){} }} children="hello" className />; // incorrect type for optional attribute
~~~~~~~~~
!!! error TS2322: Type 'true' is not assignable to type 'string'.
!!! related TS6500 tests/cases/conformance/jsx/file.tsx:5:5: The expected type comes from property 'className' which is declared here on type 'IntrinsicAttributes & HyphenProps'
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2755: No suitable overload for this call.
!!! related TS2322 tests/cases/conformance/jsx/file.tsx:55:68: Type 'true' is not assignable to type 'string'.
!!! related TS2322 tests/cases/conformance/jsx/file.tsx:55:68: Type 'true' is not assignable to type 'string'.
!!! related TS2322 tests/cases/conformance/jsx/file.tsx:55:68: Type 'true' is not assignable to type 'string'.
const b8 = <MainButton data-format />; // incorrect type for specified hyphanated name
~~~~~~~~~~~
!!! error TS2322: Type 'true' is not assignable to type 'string'.
!!! related TS6500 tests/cases/conformance/jsx/file.tsx:17:5: The expected type comes from property 'data-format' which is declared here on type 'IntrinsicAttributes & HyphenProps'
~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2755: No suitable overload for this call.
!!! related TS2757 tests/cases/conformance/jsx/file.tsx:56:13: Overload 1 of 3, '(buttonProps: ButtonProps): Element', gave the following error.
Property 'onClick' is missing in type '{ data-format: true; }' but required in type 'ButtonProps'.
!!! related TS2757 tests/cases/conformance/jsx/file.tsx:56:13: Overload 2 of 3, '(linkProps: LinkProps): Element', gave the following error.
Property 'to' is missing in type '{ data-format: true; }' but required in type 'LinkProps'.
!!! related TS2322 tests/cases/conformance/jsx/file.tsx:56:24: Type 'true' is not assignable to type 'string'.

View File

@ -113,9 +113,9 @@ const b0 = <MainButton to='/some/path' onClick={(e)=>{}}>GO</MainButton>; // ex
><MainButton to='/some/path' onClick={(e)=>{}}>GO</MainButton> : JSX.Element
>MainButton : { (buttonProps: ButtonProps): JSX.Element; (linkProps: LinkProps): JSX.Element; (hyphenProps: HyphenProps): JSX.Element; }
>to : string
>onClick : (e: any) => void
>(e)=>{} : (e: any) => void
>e : any
>onClick : (e: React.MouseEvent<any>) => void
>(e)=>{} : (e: React.MouseEvent<any>) => void
>e : React.MouseEvent<any>
>MainButton : { (buttonProps: ButtonProps): JSX.Element; (linkProps: LinkProps): JSX.Element; (hyphenProps: HyphenProps): JSX.Element; }
const b1 = <MainButton onClick={(e: any)=> {}} {...obj0}>Hello world</MainButton>; // extra property;