From bae3baa88b227d1ea71e0291480fe853a94ac4a5 Mon Sep 17 00:00:00 2001
From: o-m12a
Date: Thu, 1 May 2025 12:54:59 +0900
Subject: [PATCH 1/2] get arguments in addition to a head message
---
src/compiler/checker.ts | 67 +++++++++++++++++++++--------------------
1 file changed, 34 insertions(+), 33 deletions(-)
diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts
index be3965258a516..832312cd28ad1 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.Unable_to_resolve_signature_of_property_decorator_when_called_as_an_expression];
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 {
From dd2a58126988f87bbf21661e15e969c7f0ec4109 Mon Sep 17 00:00:00 2001
From: o-m12a
Date: Thu, 1 May 2025 13:10:36 +0900
Subject: [PATCH 2/2] make an error message related to the `PropertyDecorator`
kinder
---
src/compiler/checker.ts | 2 +-
src/compiler/diagnosticMessages.json | 2 +-
.../baselines/reference/decoratorOnClassProperty6.errors.txt | 4 ++--
.../baselines/reference/decoratorOnClassProperty7.errors.txt | 4 ++--
4 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts
index 832312cd28ad1..c32e959659230 100644
--- a/src/compiler/checker.ts
+++ b/src/compiler/checker.ts
@@ -37144,7 +37144,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
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:
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