diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index be3965258a516..c32e959659230 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -36109,7 +36109,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return constructorSymbol === globalPromiseSymbol; } - function getArgumentArityError(node: CallLikeExpression, signatures: readonly Signature[], args: readonly Expression[], headMessage?: DiagnosticMessage) { + function getArgumentArityError(node: CallLikeExpression, signatures: readonly Signature[], args: readonly Expression[], headMessageAndArgs?: DiagnosticAndArguments) { const spreadIndex = getSpreadArgumentIndex(args); if (spreadIndex > -1) { return createDiagnosticForNode(args[spreadIndex], Diagnostics.A_spread_argument_must_either_have_a_tuple_type_or_be_passed_to_a_rest_parameter); @@ -36150,9 +36150,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (min < args.length && args.length < max) { // between min and max, but with no matching overload - if (headMessage) { + if (headMessageAndArgs) { let chain = chainDiagnosticMessages(/*details*/ undefined, Diagnostics.No_overload_expects_0_arguments_but_overloads_do_exist_that_expect_either_1_or_2_arguments, args.length, maxBelow, minAbove); - chain = chainDiagnosticMessages(chain, headMessage); + chain = chainDiagnosticMessages(chain, ...headMessageAndArgs); return getDiagnosticForCallNode(node, chain); } return getDiagnosticForCallNode(node, Diagnostics.No_overload_expects_0_arguments_but_overloads_do_exist_that_expect_either_1_or_2_arguments, args.length, maxBelow, minAbove); @@ -36160,9 +36160,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { else if (args.length < min) { // too short: put the error span on the call expression, not any of the args let diagnostic: Diagnostic; - if (headMessage) { + if (headMessageAndArgs) { let chain = chainDiagnosticMessages(/*details*/ undefined, error, parameterRange, args.length); - chain = chainDiagnosticMessages(chain, headMessage); + chain = chainDiagnosticMessages(chain, ...headMessageAndArgs); diagnostic = getDiagnosticForCallNode(node, chain); } else { @@ -36187,25 +36187,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { end++; } setTextRangePosEnd(errorSpan, pos, end); - if (headMessage) { + if (headMessageAndArgs) { let chain = chainDiagnosticMessages(/*details*/ undefined, error, parameterRange, args.length); - chain = chainDiagnosticMessages(chain, headMessage); + chain = chainDiagnosticMessages(chain, ...headMessageAndArgs); return createDiagnosticForNodeArrayFromMessageChain(getSourceFileOfNode(node), errorSpan, chain); } return createDiagnosticForNodeArray(getSourceFileOfNode(node), errorSpan, error, parameterRange, args.length); } } - function getTypeArgumentArityError(node: Node, signatures: readonly Signature[], typeArguments: NodeArray, headMessage?: DiagnosticMessage) { + function getTypeArgumentArityError(node: Node, signatures: readonly Signature[], typeArguments: NodeArray, headMessageAndArgs?: DiagnosticAndArguments) { const argCount = typeArguments.length; // No overloads exist if (signatures.length === 1) { const sig = signatures[0]; const min = getMinTypeArgumentCount(sig.typeParameters); const max = length(sig.typeParameters); - if (headMessage) { + if (headMessageAndArgs) { let chain = chainDiagnosticMessages(/*details*/ undefined, Diagnostics.Expected_0_type_arguments_but_got_1, min < max ? min + "-" + max : min, argCount); - chain = chainDiagnosticMessages(chain, headMessage); + chain = chainDiagnosticMessages(chain, ...headMessageAndArgs); return createDiagnosticForNodeArrayFromMessageChain(getSourceFileOfNode(node), typeArguments, chain); } return createDiagnosticForNodeArray(getSourceFileOfNode(node), typeArguments, Diagnostics.Expected_0_type_arguments_but_got_1, min < max ? min + "-" + max : min, argCount); @@ -36224,22 +36224,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } if (belowArgCount !== -Infinity && aboveArgCount !== Infinity) { - if (headMessage) { + if (headMessageAndArgs) { let chain = chainDiagnosticMessages(/*details*/ undefined, Diagnostics.No_overload_expects_0_type_arguments_but_overloads_do_exist_that_expect_either_1_or_2_type_arguments, argCount, belowArgCount, aboveArgCount); - chain = chainDiagnosticMessages(chain, headMessage); + chain = chainDiagnosticMessages(chain, ...headMessageAndArgs); return createDiagnosticForNodeArrayFromMessageChain(getSourceFileOfNode(node), typeArguments, chain); } return createDiagnosticForNodeArray(getSourceFileOfNode(node), typeArguments, Diagnostics.No_overload_expects_0_type_arguments_but_overloads_do_exist_that_expect_either_1_or_2_type_arguments, argCount, belowArgCount, aboveArgCount); } - if (headMessage) { + if (headMessageAndArgs) { let chain = chainDiagnosticMessages(/*details*/ undefined, Diagnostics.Expected_0_type_arguments_but_got_1, belowArgCount === -Infinity ? aboveArgCount : belowArgCount, argCount); - chain = chainDiagnosticMessages(chain, headMessage); + chain = chainDiagnosticMessages(chain, ...headMessageAndArgs); return createDiagnosticForNodeArrayFromMessageChain(getSourceFileOfNode(node), typeArguments, chain); } return createDiagnosticForNodeArray(getSourceFileOfNode(node), typeArguments, Diagnostics.Expected_0_type_arguments_but_got_1, belowArgCount === -Infinity ? aboveArgCount : belowArgCount, argCount); } - function resolveCall(node: CallLikeExpression, signatures: readonly Signature[], candidatesOutArray: Signature[] | undefined, checkMode: CheckMode, callChainFlags: SignatureFlags, headMessage?: DiagnosticMessage): Signature { + function resolveCall(node: CallLikeExpression, signatures: readonly Signature[], candidatesOutArray: Signature[] | undefined, checkMode: CheckMode, callChainFlags: SignatureFlags, headMessageAndArgs?: DiagnosticAndArguments): Signature { const isTaggedTemplate = node.kind === SyntaxKind.TaggedTemplateExpression; const isDecorator = node.kind === SyntaxKind.Decorator; const isJsxOpeningOrSelfClosingElement = isJsxOpeningLikeElement(node); @@ -36370,8 +36370,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // If the call expression is a synthetic call to a `[Symbol.hasInstance]` method then we will produce a head // message when reporting diagnostics that explains how we got to `right[Symbol.hasInstance](left)` from // `left instanceof right`, as it pertains to "Argument" related messages reported for the call. - if (!headMessage && isInstanceof) { - headMessage = Diagnostics.The_left_hand_side_of_an_instanceof_expression_must_be_assignable_to_the_first_argument_of_the_right_hand_side_s_Symbol_hasInstance_method; + if (!headMessageAndArgs && isInstanceof) { + headMessageAndArgs = [Diagnostics.The_left_hand_side_of_an_instanceof_expression_must_be_assignable_to_the_first_argument_of_the_right_hand_side_s_Symbol_hasInstance_method]; } if (candidatesForArgumentError) { if (candidatesForArgumentError.length === 1 || candidatesForArgumentError.length > 3) { @@ -36381,8 +36381,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { chain = chainDiagnosticMessages(chain, Diagnostics.The_last_overload_gave_the_following_error); chain = chainDiagnosticMessages(chain, Diagnostics.No_overload_matches_this_call); } - if (headMessage) { - chain = chainDiagnosticMessages(chain, headMessage); + if (headMessageAndArgs) { + chain = chainDiagnosticMessages(chain, ...headMessageAndArgs); } const diags = getSignatureApplicabilityError(node, args, last, assignableRelation, CheckMode.Normal, /*reportErrors*/ true, () => chain, /*inferenceContext*/ undefined); if (diags) { @@ -36427,8 +36427,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { map(diags, createDiagnosticMessageChainFromDiagnostic), Diagnostics.No_overload_matches_this_call, ); - if (headMessage) { - chain = chainDiagnosticMessages(chain, headMessage); + if (headMessageAndArgs) { + chain = chainDiagnosticMessages(chain, ...headMessageAndArgs); } // The below is a spread to guarantee we get a new (mutable) array - our `flatMap` helper tries to do "smart" optimizations where it reuses input // arrays and the emptyArray singleton where possible, which is decidedly not what we want while we're still constructing this diagnostic @@ -36446,18 +36446,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } else if (candidateForArgumentArityError) { - diagnostics.add(getArgumentArityError(node, [candidateForArgumentArityError], args, headMessage)); + diagnostics.add(getArgumentArityError(node, [candidateForArgumentArityError], args, headMessageAndArgs)); } else if (candidateForTypeArgumentError) { + const [headMessage] = headMessageAndArgs ?? []; checkTypeArguments(candidateForTypeArgumentError, (node as CallExpression | TaggedTemplateExpression | JsxOpeningLikeElement).typeArguments!, /*reportErrors*/ true, headMessage); } else if (!isJsxOpenFragment) { const signaturesWithCorrectTypeArgumentArity = filter(signatures, s => hasCorrectTypeArgumentArity(s, typeArguments)); if (signaturesWithCorrectTypeArgumentArity.length === 0) { - diagnostics.add(getTypeArgumentArityError(node, signatures, typeArguments!, headMessage)); + diagnostics.add(getTypeArgumentArityError(node, signatures, typeArguments!, headMessageAndArgs)); } else { - diagnostics.add(getArgumentArityError(node, signaturesWithCorrectTypeArgumentArity, args, headMessage)); + diagnostics.add(getArgumentArityError(node, signaturesWithCorrectTypeArgumentArity, args, headMessageAndArgs)); } } } @@ -37131,24 +37132,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } /** - * Gets the localized diagnostic head message to use for errors when resolving a decorator as a call expression. + * Gets the localized diagnostic head message and its arguments to use for errors when resolving a decorator as a call expression. */ - function getDiagnosticHeadMessageForDecoratorResolution(node: Decorator) { + function getDiagnosticHeadMessageAndArgsForDecoratorResolution(node: Decorator): DiagnosticAndArguments { switch (node.parent.kind) { case SyntaxKind.ClassDeclaration: case SyntaxKind.ClassExpression: - return Diagnostics.Unable_to_resolve_signature_of_class_decorator_when_called_as_an_expression; + return [Diagnostics.Unable_to_resolve_signature_of_class_decorator_when_called_as_an_expression]; case SyntaxKind.Parameter: - return Diagnostics.Unable_to_resolve_signature_of_parameter_decorator_when_called_as_an_expression; + return [Diagnostics.Unable_to_resolve_signature_of_parameter_decorator_when_called_as_an_expression]; case SyntaxKind.PropertyDeclaration: - return Diagnostics.Unable_to_resolve_signature_of_property_decorator_when_called_as_an_expression; + return [Diagnostics.Expression_type_is_not_assignable_to_decorator_type_PropertyDecorator_Ensure_0_has_a_type_assignable_to_PropertyDecorator, getTextOfNode(node)]; case SyntaxKind.MethodDeclaration: case SyntaxKind.GetAccessor: case SyntaxKind.SetAccessor: - return Diagnostics.Unable_to_resolve_signature_of_method_decorator_when_called_as_an_expression; + return [Diagnostics.Unable_to_resolve_signature_of_method_decorator_when_called_as_an_expression]; default: return Debug.fail(); @@ -37177,10 +37178,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return resolveErrorCall(node); } - const headMessage = getDiagnosticHeadMessageForDecoratorResolution(node); + const headMessageAndArgs = getDiagnosticHeadMessageAndArgsForDecoratorResolution(node); if (!callSignatures.length) { const errorDetails = invocationErrorDetails(node.expression, apparentType, SignatureKind.Call); - const messageChain = chainDiagnosticMessages(errorDetails.messageChain, headMessage); + const messageChain = chainDiagnosticMessages(errorDetails.messageChain, ...headMessageAndArgs); const diag = createDiagnosticForNodeFromMessageChain(getSourceFileOfNode(node.expression), node.expression, messageChain); if (errorDetails.relatedMessage) { addRelatedInfo(diag, createDiagnosticForNode(node.expression, errorDetails.relatedMessage)); @@ -37190,7 +37191,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return resolveErrorCall(node); } - return resolveCall(node, callSignatures, candidatesOutArray, checkMode, SignatureFlags.None, headMessage); + return resolveCall(node, callSignatures, candidatesOutArray, checkMode, SignatureFlags.None, headMessageAndArgs); } function createSignatureForJSXIntrinsic(node: JsxCallLike, result: Type): Signature { diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index be2fe3957b20a..98dd89d84a668 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -759,7 +759,7 @@ "category": "Error", "code": 1239 }, - "Unable to resolve signature of property decorator when called as an expression.": { + "Expression type is not assignable to decorator type 'PropertyDecorator'. Ensure '{0}' has a type assignable to 'PropertyDecorator'.": { "category": "Error", "code": 1240 }, diff --git a/tests/baselines/reference/decoratorOnClassProperty6.errors.txt b/tests/baselines/reference/decoratorOnClassProperty6.errors.txt index 81048644fd0f6..31ec826b5422b 100644 --- a/tests/baselines/reference/decoratorOnClassProperty6.errors.txt +++ b/tests/baselines/reference/decoratorOnClassProperty6.errors.txt @@ -1,4 +1,4 @@ -decoratorOnClassProperty6.ts(4,6): error TS1240: Unable to resolve signature of property decorator when called as an expression. +decoratorOnClassProperty6.ts(4,6): error TS1240: Expression type is not assignable to decorator type 'PropertyDecorator'. Ensure '@dec' has a type assignable to 'PropertyDecorator'. The runtime will invoke the decorator with 2 arguments, but the decorator expects 1. @@ -8,6 +8,6 @@ decoratorOnClassProperty6.ts(4,6): error TS1240: Unable to resolve signature of class C { @dec prop; ~~~ -!!! error TS1240: Unable to resolve signature of property decorator when called as an expression. +!!! error TS1240: Expression type is not assignable to decorator type 'PropertyDecorator'. Ensure '@dec' has a type assignable to 'PropertyDecorator'. !!! error TS1240: The runtime will invoke the decorator with 2 arguments, but the decorator expects 1. } \ No newline at end of file diff --git a/tests/baselines/reference/decoratorOnClassProperty7.errors.txt b/tests/baselines/reference/decoratorOnClassProperty7.errors.txt index d81423a074b18..96754945492c8 100644 --- a/tests/baselines/reference/decoratorOnClassProperty7.errors.txt +++ b/tests/baselines/reference/decoratorOnClassProperty7.errors.txt @@ -1,4 +1,4 @@ -decoratorOnClassProperty7.ts(4,5): error TS1240: Unable to resolve signature of property decorator when called as an expression. +decoratorOnClassProperty7.ts(4,5): error TS1240: Expression type is not assignable to decorator type 'PropertyDecorator'. Ensure '@dec' has a type assignable to 'PropertyDecorator'. The runtime will invoke the decorator with 2 arguments, but the decorator expects 3. @@ -8,7 +8,7 @@ decoratorOnClassProperty7.ts(4,5): error TS1240: Unable to resolve signature of class C { @dec prop; ~~~~ -!!! error TS1240: Unable to resolve signature of property decorator when called as an expression. +!!! error TS1240: Expression type is not assignable to decorator type 'PropertyDecorator'. Ensure '@dec' has a type assignable to 'PropertyDecorator'. !!! error TS1240: The runtime will invoke the decorator with 2 arguments, but the decorator expects 3. !!! related TS6210 decoratorOnClassProperty7.ts:1:70: An argument for 'paramIndex' was not provided. } \ No newline at end of file