Skip to content

Commit 32f1db0

Browse files
srujzsCommit Queue
authored andcommitted
[dart:js_interop] Add missing checks for toJSCaptureThis
Fixes #61439 These checks exist for toJS but were not added when we introduced toJSCaptureThis. Error wording is slightly modified to be consistent. Change-Id: I12c861aacecc2bfed255be9f26c99bf2f1c02ebd Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/449661 Reviewed-by: Johnni Winther <[email protected]> Commit-Queue: Srujan Gaddam <[email protected]> Reviewed-by: Ömer Ağacan <[email protected]>
1 parent 7bdc2bb commit 32f1db0

File tree

8 files changed

+195
-91
lines changed

8 files changed

+195
-91
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,10 @@ instead.
118118
- For object literals created from extension type factories, the `@JS()`
119119
annotation can now be used to change the name of keys in JavaScript. See
120120
[#55138][] for more details.
121+
- Compile-time checks for `Function.toJS` now apply to `toJSCaptureThis` as
122+
well. Specifically, the function should be a statically known type, cannot
123+
contain invalid types in its signature, cannot have any type parameters, and
124+
cannot have any named parameters.
121125

122126
[#59830]: https://github.com/dart-lang/sdk/issues/59830
123127
[#55138]: https://github.com/dart-lang/sdk/issues/55138

pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart

Lines changed: 101 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -9721,21 +9721,114 @@ const MessageCode codeJsInteropExternalMemberNotJSAnnotated = const MessageCode(
97219721
);
97229722

97239723
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
9724-
const MessageCode codeJsInteropFunctionToJSNamedParameters = const MessageCode(
9724+
const Template<
9725+
Message Function(String conversion),
9726+
Message Function({required String conversion})
9727+
>
9728+
codeJsInteropFunctionToJSNamedParameters = const Template(
97259729
"JsInteropFunctionToJSNamedParameters",
9726-
problemMessage:
9727-
r"""Functions converted via `toJS` cannot declare named parameters.""",
9728-
correctionMessage:
9730+
problemMessageTemplate:
9731+
r"""Functions converted via '#conversion' cannot declare named parameters.""",
9732+
correctionMessageTemplate:
97299733
r"""Remove the declared named parameters from the function.""",
9734+
withArgumentsOld: _withArgumentsOldJsInteropFunctionToJSNamedParameters,
9735+
withArguments: _withArgumentsJsInteropFunctionToJSNamedParameters,
97309736
);
97319737

97329738
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
9733-
const MessageCode codeJsInteropFunctionToJSTypeParameters = const MessageCode(
9739+
Message _withArgumentsJsInteropFunctionToJSNamedParameters({
9740+
required String conversion,
9741+
}) {
9742+
var conversion_0 = conversions.validateString(conversion);
9743+
return new Message(
9744+
codeJsInteropFunctionToJSNamedParameters,
9745+
problemMessage:
9746+
"""Functions converted via '${conversion_0}' cannot declare named parameters.""",
9747+
correctionMessage:
9748+
"""Remove the declared named parameters from the function.""",
9749+
arguments: {'conversion': conversion},
9750+
);
9751+
}
9752+
9753+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
9754+
Message _withArgumentsOldJsInteropFunctionToJSNamedParameters(
9755+
String conversion,
9756+
) => _withArgumentsJsInteropFunctionToJSNamedParameters(conversion: conversion);
9757+
9758+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
9759+
const Template<
9760+
Message Function(String conversion),
9761+
Message Function({required String conversion})
9762+
>
9763+
codeJsInteropFunctionToJSTypeParameters = const Template(
97349764
"JsInteropFunctionToJSTypeParameters",
9735-
problemMessage:
9736-
r"""Functions converted via `toJS` cannot declare type parameters.""",
9737-
correctionMessage:
9765+
problemMessageTemplate:
9766+
r"""Functions converted via '#conversion' cannot declare type parameters.""",
9767+
correctionMessageTemplate:
97389768
r"""Remove the declared type parameters from the function.""",
9769+
withArgumentsOld: _withArgumentsOldJsInteropFunctionToJSTypeParameters,
9770+
withArguments: _withArgumentsJsInteropFunctionToJSTypeParameters,
9771+
);
9772+
9773+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
9774+
Message _withArgumentsJsInteropFunctionToJSTypeParameters({
9775+
required String conversion,
9776+
}) {
9777+
var conversion_0 = conversions.validateString(conversion);
9778+
return new Message(
9779+
codeJsInteropFunctionToJSTypeParameters,
9780+
problemMessage:
9781+
"""Functions converted via '${conversion_0}' cannot declare type parameters.""",
9782+
correctionMessage:
9783+
"""Remove the declared type parameters from the function.""",
9784+
arguments: {'conversion': conversion},
9785+
);
9786+
}
9787+
9788+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
9789+
Message _withArgumentsOldJsInteropFunctionToJSTypeParameters(
9790+
String conversion,
9791+
) => _withArgumentsJsInteropFunctionToJSTypeParameters(conversion: conversion);
9792+
9793+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
9794+
const Template<
9795+
Message Function(String conversion, String string2),
9796+
Message Function({required String conversion, required String string2})
9797+
>
9798+
codeJsInteropFunctionToJSTypeViolation = const Template(
9799+
"JsInteropFunctionToJSTypeViolation",
9800+
problemMessageTemplate:
9801+
r"""Function converted via '#conversion' contains invalid types in its function signature: '#string2'.""",
9802+
correctionMessageTemplate:
9803+
r"""Use one of these valid types instead: JS types from 'dart:js_interop', ExternalDartReference, void, bool, num, double, int, String, extension types that erase to one of these types, '@staticInterop' types, 'dart:html' types when compiling to JS, or a type parameter that is a subtype of a valid non-primitive type.""",
9804+
withArgumentsOld: _withArgumentsOldJsInteropFunctionToJSTypeViolation,
9805+
withArguments: _withArgumentsJsInteropFunctionToJSTypeViolation,
9806+
);
9807+
9808+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
9809+
Message _withArgumentsJsInteropFunctionToJSTypeViolation({
9810+
required String conversion,
9811+
required String string2,
9812+
}) {
9813+
var conversion_0 = conversions.validateString(conversion);
9814+
var string2_0 = conversions.validateString(string2);
9815+
return new Message(
9816+
codeJsInteropFunctionToJSTypeViolation,
9817+
problemMessage:
9818+
"""Function converted via '${conversion_0}' contains invalid types in its function signature: '${string2_0}'.""",
9819+
correctionMessage:
9820+
"""Use one of these valid types instead: JS types from 'dart:js_interop', ExternalDartReference, void, bool, num, double, int, String, extension types that erase to one of these types, '@staticInterop' types, 'dart:html' types when compiling to JS, or a type parameter that is a subtype of a valid non-primitive type.""",
9821+
arguments: {'conversion': conversion, 'string2': string2},
9822+
);
9823+
}
9824+
9825+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
9826+
Message _withArgumentsOldJsInteropFunctionToJSTypeViolation(
9827+
String conversion,
9828+
String string2,
9829+
) => _withArgumentsJsInteropFunctionToJSTypeViolation(
9830+
conversion: conversion,
9831+
string2: string2,
97399832
);
97409833

97419834
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -10226,44 +10319,6 @@ Message _withArgumentsOldJsInteropStaticInteropTearOffsDisallowed(
1022610319
name: name,
1022710320
);
1022810321

10229-
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
10230-
const Template<
10231-
Message Function(String string2),
10232-
Message Function({required String string2})
10233-
>
10234-
codeJsInteropStaticInteropToJSFunctionTypeViolation = const Template(
10235-
"JsInteropStaticInteropToJSFunctionTypeViolation",
10236-
problemMessageTemplate:
10237-
r"""Function converted via 'toJS' contains invalid types in its function signature: '#string2'.""",
10238-
correctionMessageTemplate:
10239-
r"""Use one of these valid types instead: JS types from 'dart:js_interop', ExternalDartReference, void, bool, num, double, int, String, extension types that erase to one of these types, '@staticInterop' types, 'dart:html' types when compiling to JS, or a type parameter that is a subtype of a valid non-primitive type.""",
10240-
withArgumentsOld:
10241-
_withArgumentsOldJsInteropStaticInteropToJSFunctionTypeViolation,
10242-
withArguments: _withArgumentsJsInteropStaticInteropToJSFunctionTypeViolation,
10243-
);
10244-
10245-
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
10246-
Message _withArgumentsJsInteropStaticInteropToJSFunctionTypeViolation({
10247-
required String string2,
10248-
}) {
10249-
var string2_0 = conversions.validateString(string2);
10250-
return new Message(
10251-
codeJsInteropStaticInteropToJSFunctionTypeViolation,
10252-
problemMessage:
10253-
"""Function converted via 'toJS' contains invalid types in its function signature: '${string2_0}'.""",
10254-
correctionMessage:
10255-
"""Use one of these valid types instead: JS types from 'dart:js_interop', ExternalDartReference, void, bool, num, double, int, String, extension types that erase to one of these types, '@staticInterop' types, 'dart:html' types when compiling to JS, or a type parameter that is a subtype of a valid non-primitive type.""",
10256-
arguments: {'string2': string2},
10257-
);
10258-
}
10259-
10260-
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
10261-
Message _withArgumentsOldJsInteropStaticInteropToJSFunctionTypeViolation(
10262-
String string2,
10263-
) => _withArgumentsJsInteropStaticInteropToJSFunctionTypeViolation(
10264-
string2: string2,
10265-
);
10266-
1026710322
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
1026810323
const Template<
1026910324
Message Function(String name),

pkg/_js_interop_checks/lib/js_interop_checks.dart

Lines changed: 36 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -13,42 +13,43 @@ import 'package:front_end/src/api_prototype/codes.dart'
1313
Message,
1414
LocatedMessage,
1515
codeDartFfiLibraryInDart2Wasm,
16+
codeJsInteropDartClassExtendsJSClass,
1617
codeJsInteropDartJsInteropAnnotationForStaticInteropOnly,
18+
codeJsInteropDisallowedInteropLibraryInDart2Wasm,
1719
codeJsInteropEnclosingClassJSAnnotation,
1820
codeJsInteropEnclosingClassJSAnnotationContext,
1921
codeJsInteropExtensionTypeMemberNotInterop,
22+
codeJsInteropExtensionTypeNotInterop,
2023
codeJsInteropExtensionTypeUsedWithWrongJsAnnotation,
2124
codeJsInteropExternalExtensionMemberOnTypeInvalid,
2225
codeJsInteropExternalExtensionMemberWithStaticDisallowed,
2326
codeJsInteropExternalMemberNotJSAnnotated,
2427
codeJsInteropFunctionToJSNamedParameters,
28+
codeJsInteropFunctionToJSRequiresStaticType,
2529
codeJsInteropFunctionToJSTypeParameters,
30+
codeJsInteropFunctionToJSTypeViolation,
2631
codeJsInteropInvalidStaticClassMemberName,
32+
codeJsInteropJSClassExtendsDartClass,
2733
codeJsInteropNamedParameters,
34+
codeJsInteropNativeClassInAnnotation,
2835
codeJsInteropNonExternalConstructor,
2936
codeJsInteropNonExternalMember,
37+
codeJsInteropNonStaticWithStaticInteropSupertype,
38+
codeJsInteropObjectLiteralConstructorPositionalParameters,
3039
codeJsInteropOperatorCannotBeRenamed,
3140
codeJsInteropOperatorsNotSupported,
41+
codeJsInteropStaticInteropExternalAccessorTypeViolation,
42+
codeJsInteropStaticInteropExternalFunctionTypeViolation,
3243
codeJsInteropStaticInteropGenerativeConstructor,
44+
codeJsInteropStaticInteropNoJSAnnotation,
3345
codeJsInteropStaticInteropParameterInitializersAreIgnored,
3446
codeJsInteropStaticInteropSyntheticConstructor,
35-
codeJsInteropDartClassExtendsJSClass,
36-
codeJsInteropDisallowedInteropLibraryInDart2Wasm,
37-
codeJsInteropJSClassExtendsDartClass,
38-
codeJsInteropNonStaticWithStaticInteropSupertype,
39-
codeJsInteropStaticInteropNoJSAnnotation,
40-
codeJsInteropStaticInteropWithInstanceMembers,
41-
codeJsInteropStaticInteropWithNonStaticSupertype,
42-
codeJsInteropObjectLiteralConstructorPositionalParameters,
43-
codeJsInteropNativeClassInAnnotation,
4447
codeJsInteropStaticInteropTearOffsDisallowed,
4548
codeJsInteropStaticInteropTrustTypesUsageNotAllowed,
4649
codeJsInteropStaticInteropTrustTypesUsedWithoutStaticInterop,
47-
codeJsInteropExtensionTypeNotInterop,
48-
codeJsInteropFunctionToJSRequiresStaticType,
49-
codeJsInteropStaticInteropExternalAccessorTypeViolation,
50-
codeJsInteropStaticInteropExternalFunctionTypeViolation,
51-
codeJsInteropStaticInteropToJSFunctionTypeViolation;
50+
codeJsInteropStaticInteropWithInstanceMembers,
51+
codeJsInteropStaticInteropWithNonStaticSupertype;
52+
5253
// Used for importing CFE utility functions for constructor tear-offs.
5354
import 'package:front_end/src/api_prototype/lowering_predicates.dart';
5455
import 'package:kernel/class_hierarchy.dart';
@@ -65,6 +66,7 @@ class JsInteropChecks extends RecursiveVisitor {
6566
final CoreTypes _coreTypes;
6667
late final ExtensionIndex extensionIndex;
6768
final Procedure _functionToJSTarget;
69+
final Procedure _functionToJSCaptureThisTarget;
6870
// Errors on constants need source information, so we use the surrounding
6971
// `ConstantExpression` as the source.
7072
ConstantExpression? _lastConstantExpression;
@@ -177,6 +179,10 @@ class JsInteropChecks extends RecursiveVisitor {
177179
'dart:js_interop',
178180
'FunctionToJSExportedDartFunction|get#toJS',
179181
),
182+
_functionToJSCaptureThisTarget = _coreTypes.index.getTopLevelProcedure(
183+
'dart:js_interop',
184+
'FunctionToJSExportedDartFunction|get#toJSCaptureThis',
185+
),
180186
_staticTypeContext = StatefulStaticTypeContext.stacked(
181187
TypeEnvironment(_coreTypes, hierarchy),
182188
),
@@ -496,7 +502,8 @@ class JsInteropChecks extends RecursiveVisitor {
496502
@override
497503
void visitStaticInvocation(StaticInvocation node) {
498504
final target = node.target;
499-
if (target == _functionToJSTarget) {
505+
if (target == _functionToJSTarget ||
506+
target == _functionToJSCaptureThisTarget) {
500507
_checkFunctionToJSCall(node);
501508
} else {
502509
// Only check generated tear-offs in StaticInvocations.
@@ -851,8 +858,8 @@ class JsInteropChecks extends RecursiveVisitor {
851858
return false;
852859
}
853860

854-
/// Checks that [node], which is a call to 'Function.toJS', is called with a
855-
/// valid function type.
861+
/// Checks that [node], which is a call to `Function.toJS` or
862+
/// `Function.toJSCaptureThis`, is called with a valid function type.
856863
void _checkFunctionToJSCall(StaticInvocation node) {
857864
void report(Message message) => _reporter.report(
858865
message,
@@ -861,20 +868,28 @@ class JsInteropChecks extends RecursiveVisitor {
861868
node.location?.file,
862869
);
863870

871+
final conversion = node.target == _functionToJSTarget
872+
? 'toJS'
873+
: 'toJSCaptureThis';
864874
final argument = node.arguments.positional.single;
865875
final functionType = argument.getStaticType(_staticTypeContext);
866876
if (functionType is! FunctionType) {
867877
report(
868878
codeJsInteropFunctionToJSRequiresStaticType.withArgumentsOld(
879+
conversion,
869880
functionType,
870881
),
871882
);
872883
} else {
873884
if (functionType.typeParameters.isNotEmpty) {
874-
report(codeJsInteropFunctionToJSTypeParameters);
885+
report(
886+
codeJsInteropFunctionToJSTypeParameters.withArgumentsOld(conversion),
887+
);
875888
}
876889
if (functionType.namedParameters.isNotEmpty) {
877-
report(codeJsInteropFunctionToJSNamedParameters);
890+
report(
891+
codeJsInteropFunctionToJSNamedParameters.withArgumentsOld(conversion),
892+
);
878893
}
879894
_reportFunctionToJSInvocationIfNotAllowedFunctionType(functionType, node);
880895
}
@@ -1187,7 +1202,8 @@ class JsInteropChecks extends RecursiveVisitor {
11871202
) {
11881203
if (!_isAllowedExternalFunctionType(functionType)) {
11891204
_reporter.report(
1190-
codeJsInteropStaticInteropToJSFunctionTypeViolation.withArgumentsOld(
1205+
codeJsInteropFunctionToJSTypeViolation.withArgumentsOld(
1206+
invocation.target == _functionToJSTarget ? 'toJS' : 'toJSCaptureThis',
11911207
_disallowedExternalFunctionTypeString(functionType),
11921208
),
11931209
invocation.fileOffset,

pkg/front_end/lib/src/codes/cfe_codes_generated.dart

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3141,13 +3141,13 @@ Message _withArgumentsOldJsInteropExtensionTypeNotInterop(
31413141

31423142
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
31433143
const Template<
3144-
Message Function(DartType type),
3145-
Message Function({required DartType type})
3144+
Message Function(String conversion, DartType type),
3145+
Message Function({required String conversion, required DartType type})
31463146
>
31473147
codeJsInteropFunctionToJSRequiresStaticType = const Template(
31483148
"JsInteropFunctionToJSRequiresStaticType",
31493149
problemMessageTemplate:
3150-
r"""`Function.toJS` requires a statically known function type, but Type '#type' is not a precise function type, e.g., `void Function()`.""",
3150+
r"""Functions converted via '#conversion' require a statically known function type, but Type '#type' is not a precise function type, e.g., `void Function()`.""",
31513151
correctionMessageTemplate:
31523152
r"""Insert an explicit cast to the expected function type.""",
31533153
withArgumentsOld: _withArgumentsOldJsInteropFunctionToJSRequiresStaticType,
@@ -3156,25 +3156,31 @@ codeJsInteropFunctionToJSRequiresStaticType = const Template(
31563156

31573157
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
31583158
Message _withArgumentsJsInteropFunctionToJSRequiresStaticType({
3159+
required String conversion,
31593160
required DartType type,
31603161
}) {
3162+
var conversion_0 = conversions.validateString(conversion);
31613163
TypeLabeler labeler = new TypeLabeler();
31623164
var type_0 = labeler.labelType(type);
31633165
return new Message(
31643166
codeJsInteropFunctionToJSRequiresStaticType,
31653167
problemMessage:
3166-
"""`Function.toJS` requires a statically known function type, but Type '${type_0}' is not a precise function type, e.g., `void Function()`.""" +
3168+
"""Functions converted via '${conversion_0}' require a statically known function type, but Type '${type_0}' is not a precise function type, e.g., `void Function()`.""" +
31673169
labeler.originMessages,
31683170
correctionMessage:
31693171
"""Insert an explicit cast to the expected function type.""",
3170-
arguments: {'type': type},
3172+
arguments: {'conversion': conversion, 'type': type},
31713173
);
31723174
}
31733175

31743176
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
31753177
Message _withArgumentsOldJsInteropFunctionToJSRequiresStaticType(
3178+
String conversion,
31763179
DartType type,
3177-
) => _withArgumentsJsInteropFunctionToJSRequiresStaticType(type: type);
3180+
) => _withArgumentsJsInteropFunctionToJSRequiresStaticType(
3181+
conversion: conversion,
3182+
type: type,
3183+
);
31783184

31793185
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
31803186
const Template<

pkg/front_end/messages.status

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ front_end/JsInteropExternalMemberNotJSAnnotated/example: missingExample # Web co
8585
front_end/JsInteropFunctionToJSNamedParameters/example: missingExample # Web compiler specific
8686
front_end/JsInteropFunctionToJSRequiresStaticType/example: missingExample # Web compiler specific
8787
front_end/JsInteropFunctionToJSTypeParameters/example: missingExample # Web compiler specific
88+
front_end/JsInteropFunctionToJSTypeViolation/example: missingExample
8889
front_end/JsInteropInvalidStaticClassMemberName/example: missingExample # Web compiler specific
8990
front_end/JsInteropIsAInvalidTypeVariable/example: missingExample # Web compiler specific
9091
front_end/JsInteropIsAObjectLiteralType/example: missingExample # Web compiler specific
@@ -370,6 +371,7 @@ front_end/JsInteropExternalMemberNotJSAnnotated/analyzerCode: missingAnalyzerCod
370371
front_end/JsInteropFunctionToJSNamedParameters/analyzerCode: missingAnalyzerCode # Web compiler specific
371372
front_end/JsInteropFunctionToJSRequiresStaticType/analyzerCode: missingAnalyzerCode # Web compiler specific
372373
front_end/JsInteropFunctionToJSTypeParameters/analyzerCode: missingAnalyzerCode # Web compiler specific
374+
front_end/JsInteropFunctionToJSTypeViolation/analyzerCode: missingAnalyzerCode
373375
front_end/JsInteropInvalidStaticClassMemberName/analyzerCode: missingAnalyzerCode
374376
front_end/JsInteropIsAInvalidTypeVariable/analyzerCode: missingAnalyzerCode # Web compiler specific
375377
front_end/JsInteropIsAObjectLiteralType/analyzerCode: missingAnalyzerCode # Web compiler specific

0 commit comments

Comments
 (0)