From 94e12177746cb45954ff331c9684e8abdb1adeef Mon Sep 17 00:00:00 2001 From: Srujan Gaddam Date: Mon, 27 Apr 2026 20:32:55 -0700 Subject: [PATCH] Reland "[dart:js_interop] Make JSFunction and JSExportedDartFunction generic" This is a reland of commit e7dbd6ba4866af42b917da42433cc651afd650b8 Original change's description: > [dart:js_interop] Make JSFunction and JSExportedDartFunction generic > > Fixes https://github.com/dart-lang/sdk/issues/54557 > > The generic type in JSExportedDartFunction corresponds to the > static type of the function it wrapped, whereas for JSFunction, > it's purely a descriptor of the JS function. > > When calling JSExportedDartFunction, a cast is now introduced > to cast it to T. > > When calling isA, the type in JSExportedDartFunction is passed > along to check that the value that is wrapped is that function > type. Because the T in JSFunction is descriptive, e.g. > isA>() does no such check. > > ____ > > Also cleans up: > > - isA() logic to use intrinsic functions > - some expectation files to be consistent for both dart2js and ddc. > > CoreLibraryReviewExempt: Backend-specific library with needed reviews. > Change-Id: I1a55c4386e416fa4ccabe06ac5051f41c2e2e95a > Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/496820 > Reviewed-by: Lasse Nielsen > Commit-Queue: Srujan Gaddam > Reviewed-by: Martin Kustermann CoreLibraryReviewExempt: Reland. Change-Id: I29d706aa4967fd80390e8cb37f8144603ec007f5 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/498100 Commit-Queue: Srujan Gaddam Reviewed-by: Martin Kustermann --- CHANGELOG.md | 12 ++ .../transformations/js_util_optimizer.dart | 8 +- .../shared_interop_transformer.dart | 131 +++++++++--------- .../functiontojs.dart.strong.expect | 28 ++-- .../functiontojs.dart.strong.modular.expect | 28 ++-- ...unctiontojs.dart.strong.transformed.expect | 4 +- .../dart2js/js_interop_transforms/isa.dart | 8 +- .../isa.dart.strong.expect | 8 +- .../isa.dart.strong.modular.expect | 8 +- .../isa.dart.strong.transformed.expect | 11 +- .../functiontojs.dart.strong.expect | 28 ++-- .../functiontojs.dart.strong.modular.expect | 28 ++-- ...unctiontojs.dart.strong.transformed.expect | 4 +- .../dartdevc/js_interop_transforms/isa.dart | 12 +- .../isa.dart.strong.expect | 6 +- .../isa.dart.strong.modular.expect | 6 +- .../isa.dart.strong.transformed.expect | 9 +- .../patch/js_allow_interop_patch.dart | 4 +- .../js_dev_runtime/private/interceptors.dart | 11 +- .../js_runtime/lib/interceptors.dart | 11 +- .../lib/js_allow_interop_patch.dart | 9 +- .../js_shared/lib/js_interop_patch.dart | 40 ++++-- .../_internal/wasm/lib/js_interop_patch.dart | 44 ++++-- sdk/lib/js_interop/js_interop.dart | 84 ++++++----- .../external_dart_reference_test.dart | 7 +- .../js/static_interop_test/isa/isa_test.dart | 32 ++++- .../js_types_static_errors_test.dart | 4 +- .../js/static_interop_test/js_types_test.dart | 40 ++++-- 28 files changed, 393 insertions(+), 232 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index abb22816a42..4cada8500c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,18 @@ cookie-dates _should_ have, but the RFC specifies a very permissive algorithm for what should be accepted. +#### `dart:js_interop` + +- `JSFunction` and `JSExportedDartFunction` are now generic. + `JSExportedDartFunction.toDart` now casts the original wrapped function to + the type argument `T`. Calls to `isA>` now also + check that the wrapped function is a `T`. Otherwise, this type argument is + purely descriptive and intended for increased static type safety. Importantly, + the runtime types of `JSFunction` and `JSExportedDartFunction` do not change. + See [#56905][] for more details. + +[#54557]: https://github.com/dart-lang/sdk/issues/54557 + ## 3.12.0 **Released on:** Unreleased diff --git a/pkg/_js_interop_checks/lib/src/transformations/js_util_optimizer.dart b/pkg/_js_interop_checks/lib/src/transformations/js_util_optimizer.dart index 2fa73eb877a..dc36f98b0c1 100644 --- a/pkg/_js_interop_checks/lib/src/transformations/js_util_optimizer.dart +++ b/pkg/_js_interop_checks/lib/src/transformations/js_util_optimizer.dart @@ -1043,12 +1043,14 @@ class JsUtilOptimizer extends Transformer { /// For the given `dart:js_interop` `JSExportedDartFunction.toDart` invocation /// [node], returns an invocation of `_jsFunctionToDart` with the given - /// `JSExportedDartFunction` argument. + /// `JSExportedDartFunction` and type arguments. StaticInvocation _lowerJSExportedDartFunctionToDart(StaticInvocation node) => StaticInvocation( _jsFunctionToDart, - Arguments([node.arguments.positional[0]]) - ..fileOffset = node.arguments.fileOffset, + Arguments( + [node.arguments.positional.first], + types: [node.arguments.types.first], + )..fileOffset = node.arguments.fileOffset, ) ..fileOffset = node.fileOffset ..parent = node.parent; diff --git a/pkg/_js_interop_checks/lib/src/transformations/shared_interop_transformer.dart b/pkg/_js_interop_checks/lib/src/transformations/shared_interop_transformer.dart index b7f935d6751..6ac643e6435 100644 --- a/pkg/_js_interop_checks/lib/src/transformations/shared_interop_transformer.dart +++ b/pkg/_js_interop_checks/lib/src/transformations/shared_interop_transformer.dart @@ -29,7 +29,6 @@ class SharedInteropTransformer extends Transformer { final Procedure _getProperty; final Procedure _globalContext; late bool _inIsATearoff; - final Procedure _instanceof; final Procedure _instanceOfString; late StaticInvocation? _invocation; final Procedure _isA; @@ -38,12 +37,13 @@ class SharedInteropTransformer extends Transformer { final Procedure _isJSBoxedDartObject; final Procedure _isJSExportedDartFunction; final Procedure _isJSObject; + final Procedure _isJSTypedArray; final Procedure _isNullableJSAny; final Procedure _isNullableJSBoxedDartObject; final Procedure _isNullableJSExportedDartFunction; final Procedure _isNullableJSObject; + final Procedure _isNullableJSTypedArray; final ExtensionTypeDeclaration _jsAny; - final ExtensionTypeDeclaration _jsFunction; final ExtensionTypeDeclaration _jsObject; final Procedure _setProperty; final Procedure _stringToJS; @@ -83,10 +83,6 @@ class SharedInteropTransformer extends Transformer { 'dart:js_interop', 'get:globalContext', ), - _instanceof = _typeEnvironment.coreTypes.index.getTopLevelProcedure( - 'dart:js_interop', - 'JSAnyUtilityExtension|instanceof', - ), _instanceOfString = _typeEnvironment.coreTypes.index.getTopLevelProcedure( 'dart:js_interop', 'JSAnyUtilityExtension|instanceOfString', @@ -111,6 +107,10 @@ class SharedInteropTransformer extends Transformer { 'dart:js_interop', '_isJSObject', ), + _isJSTypedArray = _typeEnvironment.coreTypes.index.getTopLevelProcedure( + 'dart:js_interop', + '_isJSTypedArray', + ), _isNullableJSAny = _typeEnvironment.coreTypes.index.getTopLevelProcedure( 'dart:js_interop', '_isNullableJSAny', @@ -127,14 +127,12 @@ class SharedInteropTransformer extends Transformer { ), _isNullableJSObject = _typeEnvironment.coreTypes.index .getTopLevelProcedure('dart:js_interop', '_isNullableJSObject'), + _isNullableJSTypedArray = _typeEnvironment.coreTypes.index + .getTopLevelProcedure('dart:js_interop', '_isNullableJSTypedArray'), _jsAny = _typeEnvironment.coreTypes.index.getExtensionType( 'dart:js_interop', 'JSAny', ), - _jsFunction = _typeEnvironment.coreTypes.index.getExtensionType( - 'dart:js_interop', - 'JSFunction', - ), _jsObject = _typeEnvironment.coreTypes.index.getExtensionType( 'dart:js_interop', 'JSObject', @@ -409,16 +407,20 @@ class SharedInteropTransformer extends Transformer { exportName, StaticInvocation( _functionToJS, - Arguments([ - InstanceTearOff( - InstanceAccessKind.Instance, - VariableGet(dartInstance), - firstExport.name, - interfaceTarget: firstExport, - resultType: _staticInteropMockValidator.typeParameterResolver - .resolve(firstExport.getterType), - ), - ]), + Arguments( + [ + InstanceTearOff( + InstanceAccessKind.Instance, + VariableGet(dartInstance), + firstExport.name, + interfaceTarget: firstExport, + resultType: _staticInteropMockValidator + .typeParameterResolver + .resolve(firstExport.getterType), + ), + ], + types: [_typeEnvironment.coreTypes.functionNonNullableRawType], + ), ), ), ); @@ -469,22 +471,27 @@ class SharedInteropTransformer extends Transformer { 'get', StaticInvocation( _functionToJS, - Arguments([ - FunctionExpression( - FunctionNode( - ReturnStatement( - InstanceGet( - InstanceAccessKind.Instance, - VariableGet(dartInstance), - getter.name, - interfaceTarget: getter, - resultType: resultType, + Arguments( + [ + FunctionExpression( + FunctionNode( + ReturnStatement( + InstanceGet( + InstanceAccessKind.Instance, + VariableGet(dartInstance), + getter.name, + interfaceTarget: getter, + resultType: resultType, + ), ), + returnType: resultType, ), - returnType: resultType, ), - ), - ]), + ], + types: [ + _typeEnvironment.coreTypes.functionNonNullableRawType, + ], + ), ), ), ); @@ -503,23 +510,28 @@ class SharedInteropTransformer extends Transformer { 'set', StaticInvocation( _functionToJS, - Arguments([ - FunctionExpression( - FunctionNode( - ExpressionStatement( - InstanceSet( - InstanceAccessKind.Instance, - VariableGet(dartInstance), - setter.name, - VariableGet(setterParameter), - interfaceTarget: setter, + Arguments( + [ + FunctionExpression( + FunctionNode( + ExpressionStatement( + InstanceSet( + InstanceAccessKind.Instance, + VariableGet(dartInstance), + setter.name, + VariableGet(setterParameter), + interfaceTarget: setter, + ), ), + positionalParameters: [setterParameter], + returnType: const VoidType(), ), - positionalParameters: [setterParameter], - returnType: const VoidType(), ), - ), - ]), + ], + types: [ + _typeEnvironment.coreTypes.functionNonNullableRawType, + ], + ), ), ), ); @@ -659,22 +671,20 @@ class SharedInteropTransformer extends Transformer { interopTypeNullable ? _isNullableJSExportedDartFunction : _isJSExportedDartFunction, - Arguments([VariableGet(receiverVar)]), + Arguments( + [VariableGet(receiverVar)], + types: [interopType.typeArguments.first], + ), ); break; case 'JSTypedArray' when interopTypeDecl == jsType: // Only do this special case when users are referring directly to the // `dart:js_interop` type and not some wrapper. - - // `TypedArray` doesn't exist as a property in JS, but rather as a - // superclass of all typed arrays. In order to do the most sensible - // thing here, we can use the prototype of some typed array, and check - // that the receiver is an `instanceof` that prototype. See - // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray#description - // for more details. + isJSAnyCheck = null; + nullChecksNeeded = false; check = StaticInvocation( - _instanceof, - Arguments([receiverVarAsJSAny, getInt8ArrayPrototype()]), + interopTypeNullable ? _isNullableJSTypedArray : _isJSTypedArray, + Arguments([VariableGet(receiverVar)]), ); break; case 'JSBoxedDartObject' when interopTypeDecl == jsType: @@ -844,13 +854,6 @@ class SharedInteropTransformer extends Transformer { Expression getObjectProperty() => getGlobalProperty('Object'); - Expression getInt8ArrayPrototype() => callMethodVarArgs( - getObjectProperty(), - 'getPrototypeOf', - [getGlobalProperty('Int8Array')], - ExtensionType(_jsFunction, Nullability.nonNullable), - ); - // Get a fresh object literal, using the proto to create it if one was // given. StaticInvocation getLiteral([Expression? proto]) => callMethodVarArgs( diff --git a/pkg/front_end/testcases/dart2js/js_interop_transforms/functiontojs.dart.strong.expect b/pkg/front_end/testcases/dart2js/js_interop_transforms/functiontojs.dart.strong.expect index 81d2853c428..f852e42e4bf 100644 --- a/pkg/front_end/testcases/dart2js/js_interop_transforms/functiontojs.dart.strong.expect +++ b/pkg/front_end/testcases/dart2js/js_interop_transforms/functiontojs.dart.strong.expect @@ -6,20 +6,20 @@ import "dart:core" as core; import "dart:js_interop"; static method main() → void { - js_::JSExportedDartFunction /* erasure=_interceptors::JavaScriptFunction */ jsFunction = js_::FunctionToJSExportedDartFunction|get#toJS(() → Null {}); - js_::FunctionToJSExportedDartFunction|get#toJS((core::int arg1) → core::int => arg1); - js_::FunctionToJSExportedDartFunction|get#toJS((([core::int? arg1 = #C1]) → core::int? => arg1) as () → void); - js_::FunctionToJSExportedDartFunction|get#toJS((core::int arg1, core::String arg2) → core::String => arg2); - js_::FunctionToJSExportedDartFunction|get#toJS((([core::int? arg1 = #C1, core::String? arg2 = #C1]) → core::String? => arg2) as ([core::int]) → void); - js_::FunctionToJSExportedDartFunction|get#toJS((core::int arg1, core::String arg2, js_::JSArray /* erasure=_interceptors::JSArray */ arg3) → js_::JSArray /* erasure=_interceptors::JSArray */ => arg3); - js_::FunctionToJSExportedDartFunction|get#toJS(((core::int arg1, [core::String? arg2 = #C1, js_::JSArray? /* erasure=_interceptors::JSArray? */ arg3 = #C1]) → js_::JSArray? /* erasure=_interceptors::JSArray? */ => arg3) as (core::int, [core::String]) → void); - js_::FunctionToJSExportedDartFunction|get#toJS((core::int arg1, core::String arg2, js_::JSArray /* erasure=_interceptors::JSArray */ arg3, js_::JSObject /* erasure=_interceptors::JSObject */ arg4) → js_::JSObject /* erasure=_interceptors::JSObject */ => arg4); - js_::FunctionToJSExportedDartFunction|get#toJS(((core::int arg1, core::String arg2, js_::JSArray /* erasure=_interceptors::JSArray */ arg3, [js_::JSObject? /* erasure=_interceptors::JSObject? */ arg4 = #C1]) → js_::JSObject? /* erasure=_interceptors::JSObject? */ => arg4) as (core::int, core::String, js_::JSArray /* erasure=_interceptors::JSArray */) → void); - js_::FunctionToJSExportedDartFunction|get#toJS((core::int arg1, core::String arg2, js_::JSArray /* erasure=_interceptors::JSArray */ arg3, js_::JSObject /* erasure=_interceptors::JSObject */ arg4, js_::JSPromise /* erasure=_interceptors::JSObject */ arg5) → js_::JSPromise /* erasure=_interceptors::JSObject */ => arg5); - js_::FunctionToJSExportedDartFunction|get#toJS(((core::int arg1, core::String arg2, [js_::JSArray? /* erasure=_interceptors::JSArray? */ arg3 = #C1, js_::JSObject? /* erasure=_interceptors::JSObject? */ arg4 = #C1, js_::JSPromise? /* erasure=_interceptors::JSObject? */ arg5 = #C1]) → js_::JSPromise? /* erasure=_interceptors::JSObject? */ => arg5) as (core::int, core::String, [js_::JSArray? /* erasure=_interceptors::JSArray? */, js_::JSObject? /* erasure=_interceptors::JSObject? */]) → void); - js_::FunctionToJSExportedDartFunction|get#toJS((core::int arg1, core::String arg2, js_::JSArray /* erasure=_interceptors::JSArray */ arg3, js_::JSObject /* erasure=_interceptors::JSObject */ arg4, js_::JSPromise /* erasure=_interceptors::JSObject */ arg5, js_::JSAny /* erasure=core::Object */ arg6) → js_::JSAny /* erasure=core::Object */ => arg6); - js_::FunctionToJSExportedDartFunction|get#toJS(((core::int arg1, core::String arg2, js_::JSArray /* erasure=_interceptors::JSArray */ arg3, js_::JSObject /* erasure=_interceptors::JSObject */ arg4, [js_::JSPromise? /* erasure=_interceptors::JSObject? */ arg5 = #C1, js_::JSAny? /* erasure=core::Object? */ arg6 = #C1]) → js_::JSAny? /* erasure=core::Object? */ => arg6) as (core::int, core::String, js_::JSArray /* erasure=_interceptors::JSArray */, js_::JSObject /* erasure=_interceptors::JSObject */, [js_::JSPromise? /* erasure=_interceptors::JSObject? */]) → void); - js_::JSExportedDartFunctionToFunction|get#toDart(jsFunction); + js_::JSExportedDartFunction<() → Null> /* erasure=_interceptors::JavaScriptFunction */ jsFunction = js_::FunctionToJSExportedDartFunction|get#toJS<() → Null>(() → Null {}); + js_::FunctionToJSExportedDartFunction|get#toJS<(core::int) → core::int>((core::int arg1) → core::int => arg1); + js_::FunctionToJSExportedDartFunction|get#toJS<() → void>((([core::int? arg1 = #C1]) → core::int? => arg1) as () → void); + js_::FunctionToJSExportedDartFunction|get#toJS<(core::int, core::String) → core::String>((core::int arg1, core::String arg2) → core::String => arg2); + js_::FunctionToJSExportedDartFunction|get#toJS<([core::int]) → void>((([core::int? arg1 = #C1, core::String? arg2 = #C1]) → core::String? => arg2) as ([core::int]) → void); + js_::FunctionToJSExportedDartFunction|get#toJS<(core::int, core::String, js_::JSArray /* erasure=_interceptors::JSArray */) → js_::JSArray /* erasure=_interceptors::JSArray */>((core::int arg1, core::String arg2, js_::JSArray /* erasure=_interceptors::JSArray */ arg3) → js_::JSArray /* erasure=_interceptors::JSArray */ => arg3); + js_::FunctionToJSExportedDartFunction|get#toJS<(core::int, [core::String]) → void>(((core::int arg1, [core::String? arg2 = #C1, js_::JSArray? /* erasure=_interceptors::JSArray? */ arg3 = #C1]) → js_::JSArray? /* erasure=_interceptors::JSArray? */ => arg3) as (core::int, [core::String]) → void); + js_::FunctionToJSExportedDartFunction|get#toJS<(core::int, core::String, js_::JSArray /* erasure=_interceptors::JSArray */, js_::JSObject /* erasure=_interceptors::JSObject */) → js_::JSObject /* erasure=_interceptors::JSObject */>((core::int arg1, core::String arg2, js_::JSArray /* erasure=_interceptors::JSArray */ arg3, js_::JSObject /* erasure=_interceptors::JSObject */ arg4) → js_::JSObject /* erasure=_interceptors::JSObject */ => arg4); + js_::FunctionToJSExportedDartFunction|get#toJS<(core::int, core::String, js_::JSArray /* erasure=_interceptors::JSArray */) → void>(((core::int arg1, core::String arg2, js_::JSArray /* erasure=_interceptors::JSArray */ arg3, [js_::JSObject? /* erasure=_interceptors::JSObject? */ arg4 = #C1]) → js_::JSObject? /* erasure=_interceptors::JSObject? */ => arg4) as (core::int, core::String, js_::JSArray /* erasure=_interceptors::JSArray */) → void); + js_::FunctionToJSExportedDartFunction|get#toJS<(core::int, core::String, js_::JSArray /* erasure=_interceptors::JSArray */, js_::JSObject /* erasure=_interceptors::JSObject */, js_::JSPromise /* erasure=_interceptors::JSObject */) → js_::JSPromise /* erasure=_interceptors::JSObject */>((core::int arg1, core::String arg2, js_::JSArray /* erasure=_interceptors::JSArray */ arg3, js_::JSObject /* erasure=_interceptors::JSObject */ arg4, js_::JSPromise /* erasure=_interceptors::JSObject */ arg5) → js_::JSPromise /* erasure=_interceptors::JSObject */ => arg5); + js_::FunctionToJSExportedDartFunction|get#toJS<(core::int, core::String, [js_::JSArray? /* erasure=_interceptors::JSArray? */, js_::JSObject? /* erasure=_interceptors::JSObject? */]) → void>(((core::int arg1, core::String arg2, [js_::JSArray? /* erasure=_interceptors::JSArray? */ arg3 = #C1, js_::JSObject? /* erasure=_interceptors::JSObject? */ arg4 = #C1, js_::JSPromise? /* erasure=_interceptors::JSObject? */ arg5 = #C1]) → js_::JSPromise? /* erasure=_interceptors::JSObject? */ => arg5) as (core::int, core::String, [js_::JSArray? /* erasure=_interceptors::JSArray? */, js_::JSObject? /* erasure=_interceptors::JSObject? */]) → void); + js_::FunctionToJSExportedDartFunction|get#toJS<(core::int, core::String, js_::JSArray /* erasure=_interceptors::JSArray */, js_::JSObject /* erasure=_interceptors::JSObject */, js_::JSPromise /* erasure=_interceptors::JSObject */, js_::JSAny /* erasure=core::Object */) → js_::JSAny /* erasure=core::Object */>((core::int arg1, core::String arg2, js_::JSArray /* erasure=_interceptors::JSArray */ arg3, js_::JSObject /* erasure=_interceptors::JSObject */ arg4, js_::JSPromise /* erasure=_interceptors::JSObject */ arg5, js_::JSAny /* erasure=core::Object */ arg6) → js_::JSAny /* erasure=core::Object */ => arg6); + js_::FunctionToJSExportedDartFunction|get#toJS<(core::int, core::String, js_::JSArray /* erasure=_interceptors::JSArray */, js_::JSObject /* erasure=_interceptors::JSObject */, [js_::JSPromise? /* erasure=_interceptors::JSObject? */]) → void>(((core::int arg1, core::String arg2, js_::JSArray /* erasure=_interceptors::JSArray */ arg3, js_::JSObject /* erasure=_interceptors::JSObject */ arg4, [js_::JSPromise? /* erasure=_interceptors::JSObject? */ arg5 = #C1, js_::JSAny? /* erasure=core::Object? */ arg6 = #C1]) → js_::JSAny? /* erasure=core::Object? */ => arg6) as (core::int, core::String, js_::JSArray /* erasure=_interceptors::JSArray */, js_::JSObject /* erasure=_interceptors::JSObject */, [js_::JSPromise? /* erasure=_interceptors::JSObject? */]) → void); + js_::JSExportedDartFunctionToFunction|get#toDart<() → Null>(jsFunction); } constants { diff --git a/pkg/front_end/testcases/dart2js/js_interop_transforms/functiontojs.dart.strong.modular.expect b/pkg/front_end/testcases/dart2js/js_interop_transforms/functiontojs.dart.strong.modular.expect index 81d2853c428..f852e42e4bf 100644 --- a/pkg/front_end/testcases/dart2js/js_interop_transforms/functiontojs.dart.strong.modular.expect +++ b/pkg/front_end/testcases/dart2js/js_interop_transforms/functiontojs.dart.strong.modular.expect @@ -6,20 +6,20 @@ import "dart:core" as core; import "dart:js_interop"; static method main() → void { - js_::JSExportedDartFunction /* erasure=_interceptors::JavaScriptFunction */ jsFunction = js_::FunctionToJSExportedDartFunction|get#toJS(() → Null {}); - js_::FunctionToJSExportedDartFunction|get#toJS((core::int arg1) → core::int => arg1); - js_::FunctionToJSExportedDartFunction|get#toJS((([core::int? arg1 = #C1]) → core::int? => arg1) as () → void); - js_::FunctionToJSExportedDartFunction|get#toJS((core::int arg1, core::String arg2) → core::String => arg2); - js_::FunctionToJSExportedDartFunction|get#toJS((([core::int? arg1 = #C1, core::String? arg2 = #C1]) → core::String? => arg2) as ([core::int]) → void); - js_::FunctionToJSExportedDartFunction|get#toJS((core::int arg1, core::String arg2, js_::JSArray /* erasure=_interceptors::JSArray */ arg3) → js_::JSArray /* erasure=_interceptors::JSArray */ => arg3); - js_::FunctionToJSExportedDartFunction|get#toJS(((core::int arg1, [core::String? arg2 = #C1, js_::JSArray? /* erasure=_interceptors::JSArray? */ arg3 = #C1]) → js_::JSArray? /* erasure=_interceptors::JSArray? */ => arg3) as (core::int, [core::String]) → void); - js_::FunctionToJSExportedDartFunction|get#toJS((core::int arg1, core::String arg2, js_::JSArray /* erasure=_interceptors::JSArray */ arg3, js_::JSObject /* erasure=_interceptors::JSObject */ arg4) → js_::JSObject /* erasure=_interceptors::JSObject */ => arg4); - js_::FunctionToJSExportedDartFunction|get#toJS(((core::int arg1, core::String arg2, js_::JSArray /* erasure=_interceptors::JSArray */ arg3, [js_::JSObject? /* erasure=_interceptors::JSObject? */ arg4 = #C1]) → js_::JSObject? /* erasure=_interceptors::JSObject? */ => arg4) as (core::int, core::String, js_::JSArray /* erasure=_interceptors::JSArray */) → void); - js_::FunctionToJSExportedDartFunction|get#toJS((core::int arg1, core::String arg2, js_::JSArray /* erasure=_interceptors::JSArray */ arg3, js_::JSObject /* erasure=_interceptors::JSObject */ arg4, js_::JSPromise /* erasure=_interceptors::JSObject */ arg5) → js_::JSPromise /* erasure=_interceptors::JSObject */ => arg5); - js_::FunctionToJSExportedDartFunction|get#toJS(((core::int arg1, core::String arg2, [js_::JSArray? /* erasure=_interceptors::JSArray? */ arg3 = #C1, js_::JSObject? /* erasure=_interceptors::JSObject? */ arg4 = #C1, js_::JSPromise? /* erasure=_interceptors::JSObject? */ arg5 = #C1]) → js_::JSPromise? /* erasure=_interceptors::JSObject? */ => arg5) as (core::int, core::String, [js_::JSArray? /* erasure=_interceptors::JSArray? */, js_::JSObject? /* erasure=_interceptors::JSObject? */]) → void); - js_::FunctionToJSExportedDartFunction|get#toJS((core::int arg1, core::String arg2, js_::JSArray /* erasure=_interceptors::JSArray */ arg3, js_::JSObject /* erasure=_interceptors::JSObject */ arg4, js_::JSPromise /* erasure=_interceptors::JSObject */ arg5, js_::JSAny /* erasure=core::Object */ arg6) → js_::JSAny /* erasure=core::Object */ => arg6); - js_::FunctionToJSExportedDartFunction|get#toJS(((core::int arg1, core::String arg2, js_::JSArray /* erasure=_interceptors::JSArray */ arg3, js_::JSObject /* erasure=_interceptors::JSObject */ arg4, [js_::JSPromise? /* erasure=_interceptors::JSObject? */ arg5 = #C1, js_::JSAny? /* erasure=core::Object? */ arg6 = #C1]) → js_::JSAny? /* erasure=core::Object? */ => arg6) as (core::int, core::String, js_::JSArray /* erasure=_interceptors::JSArray */, js_::JSObject /* erasure=_interceptors::JSObject */, [js_::JSPromise? /* erasure=_interceptors::JSObject? */]) → void); - js_::JSExportedDartFunctionToFunction|get#toDart(jsFunction); + js_::JSExportedDartFunction<() → Null> /* erasure=_interceptors::JavaScriptFunction */ jsFunction = js_::FunctionToJSExportedDartFunction|get#toJS<() → Null>(() → Null {}); + js_::FunctionToJSExportedDartFunction|get#toJS<(core::int) → core::int>((core::int arg1) → core::int => arg1); + js_::FunctionToJSExportedDartFunction|get#toJS<() → void>((([core::int? arg1 = #C1]) → core::int? => arg1) as () → void); + js_::FunctionToJSExportedDartFunction|get#toJS<(core::int, core::String) → core::String>((core::int arg1, core::String arg2) → core::String => arg2); + js_::FunctionToJSExportedDartFunction|get#toJS<([core::int]) → void>((([core::int? arg1 = #C1, core::String? arg2 = #C1]) → core::String? => arg2) as ([core::int]) → void); + js_::FunctionToJSExportedDartFunction|get#toJS<(core::int, core::String, js_::JSArray /* erasure=_interceptors::JSArray */) → js_::JSArray /* erasure=_interceptors::JSArray */>((core::int arg1, core::String arg2, js_::JSArray /* erasure=_interceptors::JSArray */ arg3) → js_::JSArray /* erasure=_interceptors::JSArray */ => arg3); + js_::FunctionToJSExportedDartFunction|get#toJS<(core::int, [core::String]) → void>(((core::int arg1, [core::String? arg2 = #C1, js_::JSArray? /* erasure=_interceptors::JSArray? */ arg3 = #C1]) → js_::JSArray? /* erasure=_interceptors::JSArray? */ => arg3) as (core::int, [core::String]) → void); + js_::FunctionToJSExportedDartFunction|get#toJS<(core::int, core::String, js_::JSArray /* erasure=_interceptors::JSArray */, js_::JSObject /* erasure=_interceptors::JSObject */) → js_::JSObject /* erasure=_interceptors::JSObject */>((core::int arg1, core::String arg2, js_::JSArray /* erasure=_interceptors::JSArray */ arg3, js_::JSObject /* erasure=_interceptors::JSObject */ arg4) → js_::JSObject /* erasure=_interceptors::JSObject */ => arg4); + js_::FunctionToJSExportedDartFunction|get#toJS<(core::int, core::String, js_::JSArray /* erasure=_interceptors::JSArray */) → void>(((core::int arg1, core::String arg2, js_::JSArray /* erasure=_interceptors::JSArray */ arg3, [js_::JSObject? /* erasure=_interceptors::JSObject? */ arg4 = #C1]) → js_::JSObject? /* erasure=_interceptors::JSObject? */ => arg4) as (core::int, core::String, js_::JSArray /* erasure=_interceptors::JSArray */) → void); + js_::FunctionToJSExportedDartFunction|get#toJS<(core::int, core::String, js_::JSArray /* erasure=_interceptors::JSArray */, js_::JSObject /* erasure=_interceptors::JSObject */, js_::JSPromise /* erasure=_interceptors::JSObject */) → js_::JSPromise /* erasure=_interceptors::JSObject */>((core::int arg1, core::String arg2, js_::JSArray /* erasure=_interceptors::JSArray */ arg3, js_::JSObject /* erasure=_interceptors::JSObject */ arg4, js_::JSPromise /* erasure=_interceptors::JSObject */ arg5) → js_::JSPromise /* erasure=_interceptors::JSObject */ => arg5); + js_::FunctionToJSExportedDartFunction|get#toJS<(core::int, core::String, [js_::JSArray? /* erasure=_interceptors::JSArray? */, js_::JSObject? /* erasure=_interceptors::JSObject? */]) → void>(((core::int arg1, core::String arg2, [js_::JSArray? /* erasure=_interceptors::JSArray? */ arg3 = #C1, js_::JSObject? /* erasure=_interceptors::JSObject? */ arg4 = #C1, js_::JSPromise? /* erasure=_interceptors::JSObject? */ arg5 = #C1]) → js_::JSPromise? /* erasure=_interceptors::JSObject? */ => arg5) as (core::int, core::String, [js_::JSArray? /* erasure=_interceptors::JSArray? */, js_::JSObject? /* erasure=_interceptors::JSObject? */]) → void); + js_::FunctionToJSExportedDartFunction|get#toJS<(core::int, core::String, js_::JSArray /* erasure=_interceptors::JSArray */, js_::JSObject /* erasure=_interceptors::JSObject */, js_::JSPromise /* erasure=_interceptors::JSObject */, js_::JSAny /* erasure=core::Object */) → js_::JSAny /* erasure=core::Object */>((core::int arg1, core::String arg2, js_::JSArray /* erasure=_interceptors::JSArray */ arg3, js_::JSObject /* erasure=_interceptors::JSObject */ arg4, js_::JSPromise /* erasure=_interceptors::JSObject */ arg5, js_::JSAny /* erasure=core::Object */ arg6) → js_::JSAny /* erasure=core::Object */ => arg6); + js_::FunctionToJSExportedDartFunction|get#toJS<(core::int, core::String, js_::JSArray /* erasure=_interceptors::JSArray */, js_::JSObject /* erasure=_interceptors::JSObject */, [js_::JSPromise? /* erasure=_interceptors::JSObject? */]) → void>(((core::int arg1, core::String arg2, js_::JSArray /* erasure=_interceptors::JSArray */ arg3, js_::JSObject /* erasure=_interceptors::JSObject */ arg4, [js_::JSPromise? /* erasure=_interceptors::JSObject? */ arg5 = #C1, js_::JSAny? /* erasure=core::Object? */ arg6 = #C1]) → js_::JSAny? /* erasure=core::Object? */ => arg6) as (core::int, core::String, js_::JSArray /* erasure=_interceptors::JSArray */, js_::JSObject /* erasure=_interceptors::JSObject */, [js_::JSPromise? /* erasure=_interceptors::JSObject? */]) → void); + js_::JSExportedDartFunctionToFunction|get#toDart<() → Null>(jsFunction); } constants { diff --git a/pkg/front_end/testcases/dart2js/js_interop_transforms/functiontojs.dart.strong.transformed.expect b/pkg/front_end/testcases/dart2js/js_interop_transforms/functiontojs.dart.strong.transformed.expect index fadb6a53a3f..5b27e50032b 100644 --- a/pkg/front_end/testcases/dart2js/js_interop_transforms/functiontojs.dart.strong.transformed.expect +++ b/pkg/front_end/testcases/dart2js/js_interop_transforms/functiontojs.dart.strong.transformed.expect @@ -6,7 +6,7 @@ import "dart:core" as core; import "dart:js_interop"; static method main() → void { - #lib1::JSExportedDartFunction /* erasure=_interceptors::JavaScriptFunction */ jsFunction = js_::_functionToJS0(() → Null {}); + #lib1::JSExportedDartFunction<() → Null> /* erasure=_interceptors::JavaScriptFunction */ jsFunction = js_::_functionToJS0(() → Null {}); js_::_functionToJS1((core::int arg1) → core::int => arg1); js_::_functionToJS0((([core::int? arg1 = #C1]) → core::int? => arg1) as () → void); js_::_functionToJS2((core::int arg1, core::String arg2) → core::String => arg2); @@ -19,7 +19,7 @@ static method main() → void { js_::_functionToJS4(((core::int arg1, core::String arg2, [#lib1::JSArray<#lib1::JSAny? /* erasure=core::Object? */>? /* erasure=_interceptors::JSArray? */ arg3 = #C1, #lib1::JSObject? /* erasure=_interceptors::JSObject? */ arg4 = #C1, #lib1::JSPromise<#lib1::JSAny? /* erasure=core::Object? */>? /* erasure=_interceptors::JSObject? */ arg5 = #C1]) → #lib1::JSPromise<#lib1::JSAny? /* erasure=core::Object? */>? /* erasure=_interceptors::JSObject? */ => arg5) as (core::int, core::String, [#lib1::JSArray<#lib1::JSAny? /* erasure=core::Object? */>? /* erasure=_interceptors::JSArray? */, #lib1::JSObject? /* erasure=_interceptors::JSObject? */]) → void); js_::_functionToJSN((core::int arg1, core::String arg2, #lib1::JSArray<#lib1::JSAny? /* erasure=core::Object? */> /* erasure=_interceptors::JSArray */ arg3, #lib1::JSObject /* erasure=_interceptors::JSObject */ arg4, #lib1::JSPromise<#lib1::JSAny? /* erasure=core::Object? */> /* erasure=_interceptors::JSObject */ arg5, #lib1::JSAny /* erasure=core::Object */ arg6) → #lib1::JSAny /* erasure=core::Object */ => arg6, 6); js_::_functionToJS5(((core::int arg1, core::String arg2, #lib1::JSArray<#lib1::JSAny? /* erasure=core::Object? */> /* erasure=_interceptors::JSArray */ arg3, #lib1::JSObject /* erasure=_interceptors::JSObject */ arg4, [#lib1::JSPromise<#lib1::JSAny? /* erasure=core::Object? */>? /* erasure=_interceptors::JSObject? */ arg5 = #C1, #lib1::JSAny? /* erasure=core::Object? */ arg6 = #C1]) → #lib1::JSAny? /* erasure=core::Object? */ => arg6) as (core::int, core::String, #lib1::JSArray<#lib1::JSAny? /* erasure=core::Object? */> /* erasure=_interceptors::JSArray */, #lib1::JSObject /* erasure=_interceptors::JSObject */, [#lib1::JSPromise<#lib1::JSAny? /* erasure=core::Object? */>? /* erasure=_interceptors::JSObject? */]) → void); - js_::_jsFunctionToDart(jsFunction); + js_::_jsFunctionToDart<() → Null>(jsFunction); } constants { diff --git a/pkg/front_end/testcases/dart2js/js_interop_transforms/isa.dart b/pkg/front_end/testcases/dart2js/js_interop_transforms/isa.dart index 33162014e9f..702d60aa725 100644 --- a/pkg/front_end/testcases/dart2js/js_interop_transforms/isa.dart +++ b/pkg/front_end/testcases/dart2js/js_interop_transforms/isa.dart @@ -43,15 +43,21 @@ void test(JSAny any, JSAny? nullableAny, Object obj, Object? nullableObj) { obj.isA(); obj.isA(); - any.isA(); + any.isA>(); obj.isA(); + // Check that there's a specific lowering for some JS types. any.isA(); any.isA(); any.isA(); + any.isA Function(int, [String?])>>(); obj.isA(); obj.isA(); obj.isA(); + obj + .isA< + JSExportedDartFunction Function(int, [String?])>? + >(); // User-defined types. any.isA(); diff --git a/pkg/front_end/testcases/dart2js/js_interop_transforms/isa.dart.strong.expect b/pkg/front_end/testcases/dart2js/js_interop_transforms/isa.dart.strong.expect index 3094118cfca..f81967793a6 100644 --- a/pkg/front_end/testcases/dart2js/js_interop_transforms/isa.dart.strong.expect +++ b/pkg/front_end/testcases/dart2js/js_interop_transforms/isa.dart.strong.expect @@ -72,14 +72,16 @@ static method test(js_::JSAny /* erasure=core::Object */ any, js_::JSAny? /* era js_::NullableObjectUtilExtension|isA(any); js_::NullableObjectUtilExtension|isA(obj); js_::NullableObjectUtilExtension|isA(obj); - js_::NullableObjectUtilExtension|isA /* erasure=_interceptors::JSArray */>(any); + js_::NullableObjectUtilExtension|isA /* erasure=_interceptors::JSArray */>(any); js_::NullableObjectUtilExtension|isA? /* erasure=_interceptors::JSArray? */>(obj); js_::NullableObjectUtilExtension|isA(any); js_::NullableObjectUtilExtension|isA(any); - js_::NullableObjectUtilExtension|isA(any); + js_::NullableObjectUtilExtension|isA /* erasure=_interceptors::JavaScriptFunction */>(any); + js_::NullableObjectUtilExtension|isA /* erasure=_interceptors::JSArray */> /* erasure=_interceptors::JavaScriptFunction */>(any); js_::NullableObjectUtilExtension|isA(obj); js_::NullableObjectUtilExtension|isA(obj); - js_::NullableObjectUtilExtension|isA(obj); + js_::NullableObjectUtilExtension|isA /* erasure=_interceptors::JavaScriptFunction */>(obj); + js_::NullableObjectUtilExtension|isA /* erasure=_interceptors::JSArray */>? /* erasure=_interceptors::JavaScriptFunction? */>(obj); js_::NullableObjectUtilExtension|isA(any); js_::NullableObjectUtilExtension|isA(any); js_::NullableObjectUtilExtension|isA(any); diff --git a/pkg/front_end/testcases/dart2js/js_interop_transforms/isa.dart.strong.modular.expect b/pkg/front_end/testcases/dart2js/js_interop_transforms/isa.dart.strong.modular.expect index 3094118cfca..f81967793a6 100644 --- a/pkg/front_end/testcases/dart2js/js_interop_transforms/isa.dart.strong.modular.expect +++ b/pkg/front_end/testcases/dart2js/js_interop_transforms/isa.dart.strong.modular.expect @@ -72,14 +72,16 @@ static method test(js_::JSAny /* erasure=core::Object */ any, js_::JSAny? /* era js_::NullableObjectUtilExtension|isA(any); js_::NullableObjectUtilExtension|isA(obj); js_::NullableObjectUtilExtension|isA(obj); - js_::NullableObjectUtilExtension|isA /* erasure=_interceptors::JSArray */>(any); + js_::NullableObjectUtilExtension|isA /* erasure=_interceptors::JSArray */>(any); js_::NullableObjectUtilExtension|isA? /* erasure=_interceptors::JSArray? */>(obj); js_::NullableObjectUtilExtension|isA(any); js_::NullableObjectUtilExtension|isA(any); - js_::NullableObjectUtilExtension|isA(any); + js_::NullableObjectUtilExtension|isA /* erasure=_interceptors::JavaScriptFunction */>(any); + js_::NullableObjectUtilExtension|isA /* erasure=_interceptors::JSArray */> /* erasure=_interceptors::JavaScriptFunction */>(any); js_::NullableObjectUtilExtension|isA(obj); js_::NullableObjectUtilExtension|isA(obj); - js_::NullableObjectUtilExtension|isA(obj); + js_::NullableObjectUtilExtension|isA /* erasure=_interceptors::JavaScriptFunction */>(obj); + js_::NullableObjectUtilExtension|isA /* erasure=_interceptors::JSArray */>? /* erasure=_interceptors::JavaScriptFunction? */>(obj); js_::NullableObjectUtilExtension|isA(any); js_::NullableObjectUtilExtension|isA(any); js_::NullableObjectUtilExtension|isA(any); diff --git a/pkg/front_end/testcases/dart2js/js_interop_transforms/isa.dart.strong.transformed.expect b/pkg/front_end/testcases/dart2js/js_interop_transforms/isa.dart.strong.transformed.expect index 3c0d4e9cef3..94e5fcca24a 100644 --- a/pkg/front_end/testcases/dart2js/js_interop_transforms/isa.dart.strong.transformed.expect +++ b/pkg/front_end/testcases/dart2js/js_interop_transforms/isa.dart.strong.transformed.expect @@ -3,7 +3,6 @@ library; import self as self; import "dart:js_interop" as js_; import "dart:core" as core; -import "dart:js_interop_unsafe" as js_2; import "dart:js_interop"; @@ -75,12 +74,14 @@ static method test(js_::JSAny /* erasure=core::Object */ any, js_::JSAny? /* era js_::_isNullableJSObject(obj); !(any == null) && js_::JSAnyUtilityExtension|instanceOfString(any, "Array"); obj == null || js_::_isJSAny(obj) && js_::JSAnyUtilityExtension|instanceOfString(obj as js_::JSAny? /* erasure=core::Object? */, "Array"); - !(any == null) && js_::JSAnyUtilityExtension|instanceof(any, js_2::JSObjectUnsafeUtilExtension|callMethodVarArgs(js_2::JSObjectUnsafeUtilExtension|[](js_::globalContext, "Object") as js_::JSObject /* erasure=_interceptors::JSObject */, js_::StringToJSString|get#toJS("getPrototypeOf"), [js_2::JSObjectUnsafeUtilExtension|[](js_::globalContext, "Int8Array") as js_::JSObject /* erasure=_interceptors::JSObject */])); + js_::_isJSTypedArray(any); js_::_isJSBoxedDartObject(any); - js_::_isJSExportedDartFunction(any); - !(obj == null) && (js_::_isJSAny(obj) && js_::JSAnyUtilityExtension|instanceof(obj as js_::JSAny? /* erasure=core::Object? */, js_2::JSObjectUnsafeUtilExtension|callMethodVarArgs(js_2::JSObjectUnsafeUtilExtension|[](js_::globalContext, "Object") as js_::JSObject /* erasure=_interceptors::JSObject */, js_::StringToJSString|get#toJS("getPrototypeOf"), [js_2::JSObjectUnsafeUtilExtension|[](js_::globalContext, "Int8Array") as js_::JSObject /* erasure=_interceptors::JSObject */]))); + js_::_isJSExportedDartFunction(any); + js_::_isJSExportedDartFunction<(core::int, [core::String?]) → js_::JSArray /* erasure=_interceptors::JSArray */>(any); + js_::_isJSTypedArray(obj); js_::_isJSBoxedDartObject(obj); - js_::_isJSExportedDartFunction(obj); + js_::_isJSExportedDartFunction(obj); + js_::_isNullableJSExportedDartFunction<(core::int, [core::String?]) → js_::JSArray /* erasure=_interceptors::JSArray */>(obj); !(any == null) && js_::JSAnyUtilityExtension|instanceOfString(any, "library1.CustomJSAny"); !(any == null) && js_::JSAnyUtilityExtension|instanceOfString(any, "library1.CustomJSObject"); !(any == null) && js_::JSAnyUtilityExtension|instanceOfString(any, "library1.CustomTypedArray"); diff --git a/pkg/front_end/testcases/dartdevc/js_interop_transforms/functiontojs.dart.strong.expect b/pkg/front_end/testcases/dartdevc/js_interop_transforms/functiontojs.dart.strong.expect index d4eb06f56e7..ba67a567279 100644 --- a/pkg/front_end/testcases/dartdevc/js_interop_transforms/functiontojs.dart.strong.expect +++ b/pkg/front_end/testcases/dartdevc/js_interop_transforms/functiontojs.dart.strong.expect @@ -6,20 +6,20 @@ import "dart:core" as core; import "dart:js_interop"; static method main() → void { - js_::JSExportedDartFunction /* erasure=dart._interceptors::JavaScriptFunction */ jsFunction = js_::FunctionToJSExportedDartFunction|get#toJS(() → Null {}); - js_::FunctionToJSExportedDartFunction|get#toJS((core::int arg1) → core::int => arg1); - js_::FunctionToJSExportedDartFunction|get#toJS((([core::int? arg1 = #C1]) → core::int? => arg1) as () → void); - js_::FunctionToJSExportedDartFunction|get#toJS((core::int arg1, core::String arg2) → core::String => arg2); - js_::FunctionToJSExportedDartFunction|get#toJS((([core::int? arg1 = #C1, core::String? arg2 = #C1]) → core::String? => arg2) as ([core::int]) → void); - js_::FunctionToJSExportedDartFunction|get#toJS((core::int arg1, core::String arg2, js_::JSArray /* erasure=dart._interceptors::JSArray */ arg3) → js_::JSArray /* erasure=dart._interceptors::JSArray */ => arg3); - js_::FunctionToJSExportedDartFunction|get#toJS(((core::int arg1, [core::String? arg2 = #C1, js_::JSArray? /* erasure=dart._interceptors::JSArray? */ arg3 = #C1]) → js_::JSArray? /* erasure=dart._interceptors::JSArray? */ => arg3) as (core::int, [core::String]) → void); - js_::FunctionToJSExportedDartFunction|get#toJS((core::int arg1, core::String arg2, js_::JSArray /* erasure=dart._interceptors::JSArray */ arg3, js_::JSObject /* erasure=dart._interceptors::JSObject */ arg4) → js_::JSObject /* erasure=dart._interceptors::JSObject */ => arg4); - js_::FunctionToJSExportedDartFunction|get#toJS(((core::int arg1, core::String arg2, js_::JSArray /* erasure=dart._interceptors::JSArray */ arg3, [js_::JSObject? /* erasure=dart._interceptors::JSObject? */ arg4 = #C1]) → js_::JSObject? /* erasure=dart._interceptors::JSObject? */ => arg4) as (core::int, core::String, js_::JSArray /* erasure=dart._interceptors::JSArray */) → void); - js_::FunctionToJSExportedDartFunction|get#toJS((core::int arg1, core::String arg2, js_::JSArray /* erasure=dart._interceptors::JSArray */ arg3, js_::JSObject /* erasure=dart._interceptors::JSObject */ arg4, js_::JSPromise /* erasure=dart._interceptors::JSObject */ arg5) → js_::JSPromise /* erasure=dart._interceptors::JSObject */ => arg5); - js_::FunctionToJSExportedDartFunction|get#toJS(((core::int arg1, core::String arg2, [js_::JSArray? /* erasure=dart._interceptors::JSArray? */ arg3 = #C1, js_::JSObject? /* erasure=dart._interceptors::JSObject? */ arg4 = #C1, js_::JSPromise? /* erasure=dart._interceptors::JSObject? */ arg5 = #C1]) → js_::JSPromise? /* erasure=dart._interceptors::JSObject? */ => arg5) as (core::int, core::String, [js_::JSArray? /* erasure=dart._interceptors::JSArray? */, js_::JSObject? /* erasure=dart._interceptors::JSObject? */]) → void); - js_::FunctionToJSExportedDartFunction|get#toJS((core::int arg1, core::String arg2, js_::JSArray /* erasure=dart._interceptors::JSArray */ arg3, js_::JSObject /* erasure=dart._interceptors::JSObject */ arg4, js_::JSPromise /* erasure=dart._interceptors::JSObject */ arg5, js_::JSAny /* erasure=core::Object */ arg6) → js_::JSAny /* erasure=core::Object */ => arg6); - js_::FunctionToJSExportedDartFunction|get#toJS(((core::int arg1, core::String arg2, js_::JSArray /* erasure=dart._interceptors::JSArray */ arg3, js_::JSObject /* erasure=dart._interceptors::JSObject */ arg4, [js_::JSPromise? /* erasure=dart._interceptors::JSObject? */ arg5 = #C1, js_::JSAny? /* erasure=core::Object? */ arg6 = #C1]) → js_::JSAny? /* erasure=core::Object? */ => arg6) as (core::int, core::String, js_::JSArray /* erasure=dart._interceptors::JSArray */, js_::JSObject /* erasure=dart._interceptors::JSObject */, [js_::JSPromise? /* erasure=dart._interceptors::JSObject? */]) → void); - js_::JSExportedDartFunctionToFunction|get#toDart(jsFunction); + js_::JSExportedDartFunction<() → Null> /* erasure=dart._interceptors::JavaScriptFunction */ jsFunction = js_::FunctionToJSExportedDartFunction|get#toJS<() → Null>(() → Null {}); + js_::FunctionToJSExportedDartFunction|get#toJS<(core::int) → core::int>((core::int arg1) → core::int => arg1); + js_::FunctionToJSExportedDartFunction|get#toJS<() → void>((([core::int? arg1 = #C1]) → core::int? => arg1) as () → void); + js_::FunctionToJSExportedDartFunction|get#toJS<(core::int, core::String) → core::String>((core::int arg1, core::String arg2) → core::String => arg2); + js_::FunctionToJSExportedDartFunction|get#toJS<([core::int]) → void>((([core::int? arg1 = #C1, core::String? arg2 = #C1]) → core::String? => arg2) as ([core::int]) → void); + js_::FunctionToJSExportedDartFunction|get#toJS<(core::int, core::String, js_::JSArray /* erasure=dart._interceptors::JSArray */) → js_::JSArray /* erasure=dart._interceptors::JSArray */>((core::int arg1, core::String arg2, js_::JSArray /* erasure=dart._interceptors::JSArray */ arg3) → js_::JSArray /* erasure=dart._interceptors::JSArray */ => arg3); + js_::FunctionToJSExportedDartFunction|get#toJS<(core::int, [core::String]) → void>(((core::int arg1, [core::String? arg2 = #C1, js_::JSArray? /* erasure=dart._interceptors::JSArray? */ arg3 = #C1]) → js_::JSArray? /* erasure=dart._interceptors::JSArray? */ => arg3) as (core::int, [core::String]) → void); + js_::FunctionToJSExportedDartFunction|get#toJS<(core::int, core::String, js_::JSArray /* erasure=dart._interceptors::JSArray */, js_::JSObject /* erasure=dart._interceptors::JSObject */) → js_::JSObject /* erasure=dart._interceptors::JSObject */>((core::int arg1, core::String arg2, js_::JSArray /* erasure=dart._interceptors::JSArray */ arg3, js_::JSObject /* erasure=dart._interceptors::JSObject */ arg4) → js_::JSObject /* erasure=dart._interceptors::JSObject */ => arg4); + js_::FunctionToJSExportedDartFunction|get#toJS<(core::int, core::String, js_::JSArray /* erasure=dart._interceptors::JSArray */) → void>(((core::int arg1, core::String arg2, js_::JSArray /* erasure=dart._interceptors::JSArray */ arg3, [js_::JSObject? /* erasure=dart._interceptors::JSObject? */ arg4 = #C1]) → js_::JSObject? /* erasure=dart._interceptors::JSObject? */ => arg4) as (core::int, core::String, js_::JSArray /* erasure=dart._interceptors::JSArray */) → void); + js_::FunctionToJSExportedDartFunction|get#toJS<(core::int, core::String, js_::JSArray /* erasure=dart._interceptors::JSArray */, js_::JSObject /* erasure=dart._interceptors::JSObject */, js_::JSPromise /* erasure=dart._interceptors::JSObject */) → js_::JSPromise /* erasure=dart._interceptors::JSObject */>((core::int arg1, core::String arg2, js_::JSArray /* erasure=dart._interceptors::JSArray */ arg3, js_::JSObject /* erasure=dart._interceptors::JSObject */ arg4, js_::JSPromise /* erasure=dart._interceptors::JSObject */ arg5) → js_::JSPromise /* erasure=dart._interceptors::JSObject */ => arg5); + js_::FunctionToJSExportedDartFunction|get#toJS<(core::int, core::String, [js_::JSArray? /* erasure=dart._interceptors::JSArray? */, js_::JSObject? /* erasure=dart._interceptors::JSObject? */]) → void>(((core::int arg1, core::String arg2, [js_::JSArray? /* erasure=dart._interceptors::JSArray? */ arg3 = #C1, js_::JSObject? /* erasure=dart._interceptors::JSObject? */ arg4 = #C1, js_::JSPromise? /* erasure=dart._interceptors::JSObject? */ arg5 = #C1]) → js_::JSPromise? /* erasure=dart._interceptors::JSObject? */ => arg5) as (core::int, core::String, [js_::JSArray? /* erasure=dart._interceptors::JSArray? */, js_::JSObject? /* erasure=dart._interceptors::JSObject? */]) → void); + js_::FunctionToJSExportedDartFunction|get#toJS<(core::int, core::String, js_::JSArray /* erasure=dart._interceptors::JSArray */, js_::JSObject /* erasure=dart._interceptors::JSObject */, js_::JSPromise /* erasure=dart._interceptors::JSObject */, js_::JSAny /* erasure=core::Object */) → js_::JSAny /* erasure=core::Object */>((core::int arg1, core::String arg2, js_::JSArray /* erasure=dart._interceptors::JSArray */ arg3, js_::JSObject /* erasure=dart._interceptors::JSObject */ arg4, js_::JSPromise /* erasure=dart._interceptors::JSObject */ arg5, js_::JSAny /* erasure=core::Object */ arg6) → js_::JSAny /* erasure=core::Object */ => arg6); + js_::FunctionToJSExportedDartFunction|get#toJS<(core::int, core::String, js_::JSArray /* erasure=dart._interceptors::JSArray */, js_::JSObject /* erasure=dart._interceptors::JSObject */, [js_::JSPromise? /* erasure=dart._interceptors::JSObject? */]) → void>(((core::int arg1, core::String arg2, js_::JSArray /* erasure=dart._interceptors::JSArray */ arg3, js_::JSObject /* erasure=dart._interceptors::JSObject */ arg4, [js_::JSPromise? /* erasure=dart._interceptors::JSObject? */ arg5 = #C1, js_::JSAny? /* erasure=core::Object? */ arg6 = #C1]) → js_::JSAny? /* erasure=core::Object? */ => arg6) as (core::int, core::String, js_::JSArray /* erasure=dart._interceptors::JSArray */, js_::JSObject /* erasure=dart._interceptors::JSObject */, [js_::JSPromise? /* erasure=dart._interceptors::JSObject? */]) → void); + js_::JSExportedDartFunctionToFunction|get#toDart<() → Null>(jsFunction); } constants { diff --git a/pkg/front_end/testcases/dartdevc/js_interop_transforms/functiontojs.dart.strong.modular.expect b/pkg/front_end/testcases/dartdevc/js_interop_transforms/functiontojs.dart.strong.modular.expect index d4eb06f56e7..ba67a567279 100644 --- a/pkg/front_end/testcases/dartdevc/js_interop_transforms/functiontojs.dart.strong.modular.expect +++ b/pkg/front_end/testcases/dartdevc/js_interop_transforms/functiontojs.dart.strong.modular.expect @@ -6,20 +6,20 @@ import "dart:core" as core; import "dart:js_interop"; static method main() → void { - js_::JSExportedDartFunction /* erasure=dart._interceptors::JavaScriptFunction */ jsFunction = js_::FunctionToJSExportedDartFunction|get#toJS(() → Null {}); - js_::FunctionToJSExportedDartFunction|get#toJS((core::int arg1) → core::int => arg1); - js_::FunctionToJSExportedDartFunction|get#toJS((([core::int? arg1 = #C1]) → core::int? => arg1) as () → void); - js_::FunctionToJSExportedDartFunction|get#toJS((core::int arg1, core::String arg2) → core::String => arg2); - js_::FunctionToJSExportedDartFunction|get#toJS((([core::int? arg1 = #C1, core::String? arg2 = #C1]) → core::String? => arg2) as ([core::int]) → void); - js_::FunctionToJSExportedDartFunction|get#toJS((core::int arg1, core::String arg2, js_::JSArray /* erasure=dart._interceptors::JSArray */ arg3) → js_::JSArray /* erasure=dart._interceptors::JSArray */ => arg3); - js_::FunctionToJSExportedDartFunction|get#toJS(((core::int arg1, [core::String? arg2 = #C1, js_::JSArray? /* erasure=dart._interceptors::JSArray? */ arg3 = #C1]) → js_::JSArray? /* erasure=dart._interceptors::JSArray? */ => arg3) as (core::int, [core::String]) → void); - js_::FunctionToJSExportedDartFunction|get#toJS((core::int arg1, core::String arg2, js_::JSArray /* erasure=dart._interceptors::JSArray */ arg3, js_::JSObject /* erasure=dart._interceptors::JSObject */ arg4) → js_::JSObject /* erasure=dart._interceptors::JSObject */ => arg4); - js_::FunctionToJSExportedDartFunction|get#toJS(((core::int arg1, core::String arg2, js_::JSArray /* erasure=dart._interceptors::JSArray */ arg3, [js_::JSObject? /* erasure=dart._interceptors::JSObject? */ arg4 = #C1]) → js_::JSObject? /* erasure=dart._interceptors::JSObject? */ => arg4) as (core::int, core::String, js_::JSArray /* erasure=dart._interceptors::JSArray */) → void); - js_::FunctionToJSExportedDartFunction|get#toJS((core::int arg1, core::String arg2, js_::JSArray /* erasure=dart._interceptors::JSArray */ arg3, js_::JSObject /* erasure=dart._interceptors::JSObject */ arg4, js_::JSPromise /* erasure=dart._interceptors::JSObject */ arg5) → js_::JSPromise /* erasure=dart._interceptors::JSObject */ => arg5); - js_::FunctionToJSExportedDartFunction|get#toJS(((core::int arg1, core::String arg2, [js_::JSArray? /* erasure=dart._interceptors::JSArray? */ arg3 = #C1, js_::JSObject? /* erasure=dart._interceptors::JSObject? */ arg4 = #C1, js_::JSPromise? /* erasure=dart._interceptors::JSObject? */ arg5 = #C1]) → js_::JSPromise? /* erasure=dart._interceptors::JSObject? */ => arg5) as (core::int, core::String, [js_::JSArray? /* erasure=dart._interceptors::JSArray? */, js_::JSObject? /* erasure=dart._interceptors::JSObject? */]) → void); - js_::FunctionToJSExportedDartFunction|get#toJS((core::int arg1, core::String arg2, js_::JSArray /* erasure=dart._interceptors::JSArray */ arg3, js_::JSObject /* erasure=dart._interceptors::JSObject */ arg4, js_::JSPromise /* erasure=dart._interceptors::JSObject */ arg5, js_::JSAny /* erasure=core::Object */ arg6) → js_::JSAny /* erasure=core::Object */ => arg6); - js_::FunctionToJSExportedDartFunction|get#toJS(((core::int arg1, core::String arg2, js_::JSArray /* erasure=dart._interceptors::JSArray */ arg3, js_::JSObject /* erasure=dart._interceptors::JSObject */ arg4, [js_::JSPromise? /* erasure=dart._interceptors::JSObject? */ arg5 = #C1, js_::JSAny? /* erasure=core::Object? */ arg6 = #C1]) → js_::JSAny? /* erasure=core::Object? */ => arg6) as (core::int, core::String, js_::JSArray /* erasure=dart._interceptors::JSArray */, js_::JSObject /* erasure=dart._interceptors::JSObject */, [js_::JSPromise? /* erasure=dart._interceptors::JSObject? */]) → void); - js_::JSExportedDartFunctionToFunction|get#toDart(jsFunction); + js_::JSExportedDartFunction<() → Null> /* erasure=dart._interceptors::JavaScriptFunction */ jsFunction = js_::FunctionToJSExportedDartFunction|get#toJS<() → Null>(() → Null {}); + js_::FunctionToJSExportedDartFunction|get#toJS<(core::int) → core::int>((core::int arg1) → core::int => arg1); + js_::FunctionToJSExportedDartFunction|get#toJS<() → void>((([core::int? arg1 = #C1]) → core::int? => arg1) as () → void); + js_::FunctionToJSExportedDartFunction|get#toJS<(core::int, core::String) → core::String>((core::int arg1, core::String arg2) → core::String => arg2); + js_::FunctionToJSExportedDartFunction|get#toJS<([core::int]) → void>((([core::int? arg1 = #C1, core::String? arg2 = #C1]) → core::String? => arg2) as ([core::int]) → void); + js_::FunctionToJSExportedDartFunction|get#toJS<(core::int, core::String, js_::JSArray /* erasure=dart._interceptors::JSArray */) → js_::JSArray /* erasure=dart._interceptors::JSArray */>((core::int arg1, core::String arg2, js_::JSArray /* erasure=dart._interceptors::JSArray */ arg3) → js_::JSArray /* erasure=dart._interceptors::JSArray */ => arg3); + js_::FunctionToJSExportedDartFunction|get#toJS<(core::int, [core::String]) → void>(((core::int arg1, [core::String? arg2 = #C1, js_::JSArray? /* erasure=dart._interceptors::JSArray? */ arg3 = #C1]) → js_::JSArray? /* erasure=dart._interceptors::JSArray? */ => arg3) as (core::int, [core::String]) → void); + js_::FunctionToJSExportedDartFunction|get#toJS<(core::int, core::String, js_::JSArray /* erasure=dart._interceptors::JSArray */, js_::JSObject /* erasure=dart._interceptors::JSObject */) → js_::JSObject /* erasure=dart._interceptors::JSObject */>((core::int arg1, core::String arg2, js_::JSArray /* erasure=dart._interceptors::JSArray */ arg3, js_::JSObject /* erasure=dart._interceptors::JSObject */ arg4) → js_::JSObject /* erasure=dart._interceptors::JSObject */ => arg4); + js_::FunctionToJSExportedDartFunction|get#toJS<(core::int, core::String, js_::JSArray /* erasure=dart._interceptors::JSArray */) → void>(((core::int arg1, core::String arg2, js_::JSArray /* erasure=dart._interceptors::JSArray */ arg3, [js_::JSObject? /* erasure=dart._interceptors::JSObject? */ arg4 = #C1]) → js_::JSObject? /* erasure=dart._interceptors::JSObject? */ => arg4) as (core::int, core::String, js_::JSArray /* erasure=dart._interceptors::JSArray */) → void); + js_::FunctionToJSExportedDartFunction|get#toJS<(core::int, core::String, js_::JSArray /* erasure=dart._interceptors::JSArray */, js_::JSObject /* erasure=dart._interceptors::JSObject */, js_::JSPromise /* erasure=dart._interceptors::JSObject */) → js_::JSPromise /* erasure=dart._interceptors::JSObject */>((core::int arg1, core::String arg2, js_::JSArray /* erasure=dart._interceptors::JSArray */ arg3, js_::JSObject /* erasure=dart._interceptors::JSObject */ arg4, js_::JSPromise /* erasure=dart._interceptors::JSObject */ arg5) → js_::JSPromise /* erasure=dart._interceptors::JSObject */ => arg5); + js_::FunctionToJSExportedDartFunction|get#toJS<(core::int, core::String, [js_::JSArray? /* erasure=dart._interceptors::JSArray? */, js_::JSObject? /* erasure=dart._interceptors::JSObject? */]) → void>(((core::int arg1, core::String arg2, [js_::JSArray? /* erasure=dart._interceptors::JSArray? */ arg3 = #C1, js_::JSObject? /* erasure=dart._interceptors::JSObject? */ arg4 = #C1, js_::JSPromise? /* erasure=dart._interceptors::JSObject? */ arg5 = #C1]) → js_::JSPromise? /* erasure=dart._interceptors::JSObject? */ => arg5) as (core::int, core::String, [js_::JSArray? /* erasure=dart._interceptors::JSArray? */, js_::JSObject? /* erasure=dart._interceptors::JSObject? */]) → void); + js_::FunctionToJSExportedDartFunction|get#toJS<(core::int, core::String, js_::JSArray /* erasure=dart._interceptors::JSArray */, js_::JSObject /* erasure=dart._interceptors::JSObject */, js_::JSPromise /* erasure=dart._interceptors::JSObject */, js_::JSAny /* erasure=core::Object */) → js_::JSAny /* erasure=core::Object */>((core::int arg1, core::String arg2, js_::JSArray /* erasure=dart._interceptors::JSArray */ arg3, js_::JSObject /* erasure=dart._interceptors::JSObject */ arg4, js_::JSPromise /* erasure=dart._interceptors::JSObject */ arg5, js_::JSAny /* erasure=core::Object */ arg6) → js_::JSAny /* erasure=core::Object */ => arg6); + js_::FunctionToJSExportedDartFunction|get#toJS<(core::int, core::String, js_::JSArray /* erasure=dart._interceptors::JSArray */, js_::JSObject /* erasure=dart._interceptors::JSObject */, [js_::JSPromise? /* erasure=dart._interceptors::JSObject? */]) → void>(((core::int arg1, core::String arg2, js_::JSArray /* erasure=dart._interceptors::JSArray */ arg3, js_::JSObject /* erasure=dart._interceptors::JSObject */ arg4, [js_::JSPromise? /* erasure=dart._interceptors::JSObject? */ arg5 = #C1, js_::JSAny? /* erasure=core::Object? */ arg6 = #C1]) → js_::JSAny? /* erasure=core::Object? */ => arg6) as (core::int, core::String, js_::JSArray /* erasure=dart._interceptors::JSArray */, js_::JSObject /* erasure=dart._interceptors::JSObject */, [js_::JSPromise? /* erasure=dart._interceptors::JSObject? */]) → void); + js_::JSExportedDartFunctionToFunction|get#toDart<() → Null>(jsFunction); } constants { diff --git a/pkg/front_end/testcases/dartdevc/js_interop_transforms/functiontojs.dart.strong.transformed.expect b/pkg/front_end/testcases/dartdevc/js_interop_transforms/functiontojs.dart.strong.transformed.expect index fb798b1460c..819abf77207 100644 --- a/pkg/front_end/testcases/dartdevc/js_interop_transforms/functiontojs.dart.strong.transformed.expect +++ b/pkg/front_end/testcases/dartdevc/js_interop_transforms/functiontojs.dart.strong.transformed.expect @@ -6,7 +6,7 @@ import "dart:core" as core; import "dart:js_interop"; static method main() → void { - #lib1::JSExportedDartFunction /* erasure=dart._interceptors::JavaScriptFunction */ jsFunction = js_::_functionToJS0(() → Null {}); + #lib1::JSExportedDartFunction<() → Null> /* erasure=dart._interceptors::JavaScriptFunction */ jsFunction = js_::_functionToJS0(() → Null {}); js_::_functionToJS1((core::int arg1) → core::int => arg1); js_::_functionToJS0((([core::int? arg1 = #C1]) → core::int? => arg1) as () → void); js_::_functionToJS2((core::int arg1, core::String arg2) → core::String => arg2); @@ -19,7 +19,7 @@ static method main() → void { js_::_functionToJS4(((core::int arg1, core::String arg2, [#lib1::JSArray<#lib1::JSAny? /* erasure=core::Object? */>? /* erasure=dart._interceptors::JSArray? */ arg3 = #C1, #lib1::JSObject? /* erasure=dart._interceptors::JSObject? */ arg4 = #C1, #lib1::JSPromise<#lib1::JSAny? /* erasure=core::Object? */>? /* erasure=dart._interceptors::JSObject? */ arg5 = #C1]) → #lib1::JSPromise<#lib1::JSAny? /* erasure=core::Object? */>? /* erasure=dart._interceptors::JSObject? */ => arg5) as (core::int, core::String, [#lib1::JSArray<#lib1::JSAny? /* erasure=core::Object? */>? /* erasure=dart._interceptors::JSArray? */, #lib1::JSObject? /* erasure=dart._interceptors::JSObject? */]) → void); js_::_functionToJSN((core::int arg1, core::String arg2, #lib1::JSArray<#lib1::JSAny? /* erasure=core::Object? */> /* erasure=dart._interceptors::JSArray */ arg3, #lib1::JSObject /* erasure=dart._interceptors::JSObject */ arg4, #lib1::JSPromise<#lib1::JSAny? /* erasure=core::Object? */> /* erasure=dart._interceptors::JSObject */ arg5, #lib1::JSAny /* erasure=core::Object */ arg6) → #lib1::JSAny /* erasure=core::Object */ => arg6, 6); js_::_functionToJS5(((core::int arg1, core::String arg2, #lib1::JSArray<#lib1::JSAny? /* erasure=core::Object? */> /* erasure=dart._interceptors::JSArray */ arg3, #lib1::JSObject /* erasure=dart._interceptors::JSObject */ arg4, [#lib1::JSPromise<#lib1::JSAny? /* erasure=core::Object? */>? /* erasure=dart._interceptors::JSObject? */ arg5 = #C1, #lib1::JSAny? /* erasure=core::Object? */ arg6 = #C1]) → #lib1::JSAny? /* erasure=core::Object? */ => arg6) as (core::int, core::String, #lib1::JSArray<#lib1::JSAny? /* erasure=core::Object? */> /* erasure=dart._interceptors::JSArray */, #lib1::JSObject /* erasure=dart._interceptors::JSObject */, [#lib1::JSPromise<#lib1::JSAny? /* erasure=core::Object? */>? /* erasure=dart._interceptors::JSObject? */]) → void); - js_::_jsFunctionToDart(jsFunction); + js_::_jsFunctionToDart<() → Null>(jsFunction); } constants { diff --git a/pkg/front_end/testcases/dartdevc/js_interop_transforms/isa.dart b/pkg/front_end/testcases/dartdevc/js_interop_transforms/isa.dart index b9a1e0877c7..702d60aa725 100644 --- a/pkg/front_end/testcases/dartdevc/js_interop_transforms/isa.dart +++ b/pkg/front_end/testcases/dartdevc/js_interop_transforms/isa.dart @@ -43,13 +43,21 @@ void test(JSAny any, JSAny? nullableAny, Object obj, Object? nullableObj) { obj.isA(); obj.isA(); - any.isA(); + any.isA>(); obj.isA(); - // JSTypedArray and JSBoxedDartObject handled differently. + + // Check that there's a specific lowering for some JS types. any.isA(); any.isA(); + any.isA(); + any.isA Function(int, [String?])>>(); obj.isA(); obj.isA(); + obj.isA(); + obj + .isA< + JSExportedDartFunction Function(int, [String?])>? + >(); // User-defined types. any.isA(); diff --git a/pkg/front_end/testcases/dartdevc/js_interop_transforms/isa.dart.strong.expect b/pkg/front_end/testcases/dartdevc/js_interop_transforms/isa.dart.strong.expect index 99b5d3fa7c0..24e91920b81 100644 --- a/pkg/front_end/testcases/dartdevc/js_interop_transforms/isa.dart.strong.expect +++ b/pkg/front_end/testcases/dartdevc/js_interop_transforms/isa.dart.strong.expect @@ -72,12 +72,16 @@ static method test(js_::JSAny /* erasure=core::Object */ any, js_::JSAny? /* era js_::NullableObjectUtilExtension|isA(any); js_::NullableObjectUtilExtension|isA(obj); js_::NullableObjectUtilExtension|isA(obj); - js_::NullableObjectUtilExtension|isA /* erasure=dart._interceptors::JSArray */>(any); + js_::NullableObjectUtilExtension|isA /* erasure=dart._interceptors::JSArray */>(any); js_::NullableObjectUtilExtension|isA? /* erasure=dart._interceptors::JSArray? */>(obj); js_::NullableObjectUtilExtension|isA(any); js_::NullableObjectUtilExtension|isA(any); + js_::NullableObjectUtilExtension|isA /* erasure=dart._interceptors::JavaScriptFunction */>(any); + js_::NullableObjectUtilExtension|isA /* erasure=dart._interceptors::JSArray */> /* erasure=dart._interceptors::JavaScriptFunction */>(any); js_::NullableObjectUtilExtension|isA(obj); js_::NullableObjectUtilExtension|isA(obj); + js_::NullableObjectUtilExtension|isA /* erasure=dart._interceptors::JavaScriptFunction */>(obj); + js_::NullableObjectUtilExtension|isA /* erasure=dart._interceptors::JSArray */>? /* erasure=dart._interceptors::JavaScriptFunction? */>(obj); js_::NullableObjectUtilExtension|isA(any); js_::NullableObjectUtilExtension|isA(any); js_::NullableObjectUtilExtension|isA(any); diff --git a/pkg/front_end/testcases/dartdevc/js_interop_transforms/isa.dart.strong.modular.expect b/pkg/front_end/testcases/dartdevc/js_interop_transforms/isa.dart.strong.modular.expect index 99b5d3fa7c0..24e91920b81 100644 --- a/pkg/front_end/testcases/dartdevc/js_interop_transforms/isa.dart.strong.modular.expect +++ b/pkg/front_end/testcases/dartdevc/js_interop_transforms/isa.dart.strong.modular.expect @@ -72,12 +72,16 @@ static method test(js_::JSAny /* erasure=core::Object */ any, js_::JSAny? /* era js_::NullableObjectUtilExtension|isA(any); js_::NullableObjectUtilExtension|isA(obj); js_::NullableObjectUtilExtension|isA(obj); - js_::NullableObjectUtilExtension|isA /* erasure=dart._interceptors::JSArray */>(any); + js_::NullableObjectUtilExtension|isA /* erasure=dart._interceptors::JSArray */>(any); js_::NullableObjectUtilExtension|isA? /* erasure=dart._interceptors::JSArray? */>(obj); js_::NullableObjectUtilExtension|isA(any); js_::NullableObjectUtilExtension|isA(any); + js_::NullableObjectUtilExtension|isA /* erasure=dart._interceptors::JavaScriptFunction */>(any); + js_::NullableObjectUtilExtension|isA /* erasure=dart._interceptors::JSArray */> /* erasure=dart._interceptors::JavaScriptFunction */>(any); js_::NullableObjectUtilExtension|isA(obj); js_::NullableObjectUtilExtension|isA(obj); + js_::NullableObjectUtilExtension|isA /* erasure=dart._interceptors::JavaScriptFunction */>(obj); + js_::NullableObjectUtilExtension|isA /* erasure=dart._interceptors::JSArray */>? /* erasure=dart._interceptors::JavaScriptFunction? */>(obj); js_::NullableObjectUtilExtension|isA(any); js_::NullableObjectUtilExtension|isA(any); js_::NullableObjectUtilExtension|isA(any); diff --git a/pkg/front_end/testcases/dartdevc/js_interop_transforms/isa.dart.strong.transformed.expect b/pkg/front_end/testcases/dartdevc/js_interop_transforms/isa.dart.strong.transformed.expect index cfd34bb6fcd..747fa58aeb4 100644 --- a/pkg/front_end/testcases/dartdevc/js_interop_transforms/isa.dart.strong.transformed.expect +++ b/pkg/front_end/testcases/dartdevc/js_interop_transforms/isa.dart.strong.transformed.expect @@ -3,7 +3,6 @@ library; import self as self; import "dart:js_interop" as js_; import "dart:core" as core; -import "dart:js_interop_unsafe" as js_2; import "dart:js_interop"; @@ -75,10 +74,14 @@ static method test(js_::JSAny /* erasure=core::Object */ any, js_::JSAny? /* era js_::_isNullableJSObject(obj); !(any == null) && js_::JSAnyUtilityExtension|instanceOfString(any, "Array"); obj == null || js_::_isJSAny(obj) && js_::JSAnyUtilityExtension|instanceOfString(obj as js_::JSAny? /* erasure=core::Object? */, "Array"); - !(any == null) && js_::JSAnyUtilityExtension|instanceof(any, js_2::JSObjectUnsafeUtilExtension|callMethodVarArgs(js_2::JSObjectUnsafeUtilExtension|[](js_::globalContext, "Object") as js_::JSObject /* erasure=dart._interceptors::JSObject */, js_::StringToJSString|get#toJS("getPrototypeOf"), [js_2::JSObjectUnsafeUtilExtension|[](js_::globalContext, "Int8Array") as js_::JSObject /* erasure=dart._interceptors::JSObject */])); + js_::_isJSTypedArray(any); js_::_isJSBoxedDartObject(any); - !(obj == null) && (js_::_isJSAny(obj) && js_::JSAnyUtilityExtension|instanceof(obj as js_::JSAny? /* erasure=core::Object? */, js_2::JSObjectUnsafeUtilExtension|callMethodVarArgs(js_2::JSObjectUnsafeUtilExtension|[](js_::globalContext, "Object") as js_::JSObject /* erasure=dart._interceptors::JSObject */, js_::StringToJSString|get#toJS("getPrototypeOf"), [js_2::JSObjectUnsafeUtilExtension|[](js_::globalContext, "Int8Array") as js_::JSObject /* erasure=dart._interceptors::JSObject */]))); + js_::_isJSExportedDartFunction(any); + js_::_isJSExportedDartFunction<(core::int, [core::String?]) → js_::JSArray /* erasure=dart._interceptors::JSArray */>(any); + js_::_isJSTypedArray(obj); js_::_isJSBoxedDartObject(obj); + js_::_isJSExportedDartFunction(obj); + js_::_isNullableJSExportedDartFunction<(core::int, [core::String?]) → js_::JSArray /* erasure=dart._interceptors::JSArray */>(obj); !(any == null) && js_::JSAnyUtilityExtension|instanceOfString(any, "library1.CustomJSAny"); !(any == null) && js_::JSAnyUtilityExtension|instanceOfString(any, "library1.CustomJSObject"); !(any == null) && js_::JSAnyUtilityExtension|instanceOfString(any, "library1.CustomTypedArray"); diff --git a/sdk/lib/_internal/js_dev_runtime/patch/js_allow_interop_patch.dart b/sdk/lib/_internal/js_dev_runtime/patch/js_allow_interop_patch.dart index 657a0353345..359151f76c8 100644 --- a/sdk/lib/_internal/js_dev_runtime/patch/js_allow_interop_patch.dart +++ b/sdk/lib/_internal/js_dev_runtime/patch/js_allow_interop_patch.dart @@ -353,6 +353,6 @@ _callDartFunctionFast5(callback, arg1, arg2, arg3, arg4, arg5, int length) { } } -Function _jsFunctionToDart(JavaScriptFunction f) { - return JS('Function', '#[#]', f, functionToJSProperty); +T _jsFunctionToDart(JavaScriptFunction f) { + return JS('', '#[#]', f, functionToJSProperty); } diff --git a/sdk/lib/_internal/js_dev_runtime/private/interceptors.dart b/sdk/lib/_internal/js_dev_runtime/private/interceptors.dart index 427d332fa4f..6b43f590b6b 100644 --- a/sdk/lib/_internal/js_dev_runtime/private/interceptors.dart +++ b/sdk/lib/_internal/js_dev_runtime/private/interceptors.dart @@ -311,10 +311,13 @@ class JavaScriptFunction extends LegacyJavaScriptObject implements Function {} final _functionToJSPropertyName = r'_$dart_dartClosure'; final functionToJSProperty = JS('!', "Symbol($_functionToJSPropertyName)"); -/// Returns whether [f] is a wrapped Dart function through `dart:js_interop`'s -/// conversion methods. -bool isJSExportedDartFunction(JavaScriptFunction f) => - JS('', '#.#', f, functionToJSProperty) != null; +/// Returns whether [f] is a wrapped Dart function of type [T] through +/// `dart:js_interop`'s conversion methods. +bool isJSExportedDartFunction(JavaScriptFunction f) { + final function = JS('', '#.#', f, functionToJSProperty); + // We set this value so we know it always `is Function`. + return function != null && T == Function ? true : function is T; +} /// Interceptor for JavaScript BigInt primitive values, i.e. values `x` for /// which `typeof x == "bigint"`. diff --git a/sdk/lib/_internal/js_runtime/lib/interceptors.dart b/sdk/lib/_internal/js_runtime/lib/interceptors.dart index 9a9f340d257..b73c725a5ef 100644 --- a/sdk/lib/_internal/js_runtime/lib/interceptors.dart +++ b/sdk/lib/_internal/js_runtime/lib/interceptors.dart @@ -85,10 +85,13 @@ final String DART_CLOSURE_DART_JSINTEROP_PROPERTY_NAME = getIsolateAffinityTag( r'_$dart_dartClosure_dartJSInterop', ); -/// Returns whether [f] is a wrapped Dart function through `dart:js_interop`'s -/// conversion methods. -bool isJSExportedDartFunction(JavaScriptFunction f) => - JS('', '#.#', f, DART_CLOSURE_DART_JSINTEROP_PROPERTY_NAME) != null; +/// Returns whether [f] is a wrapped Dart function of type [T] through +/// `dart:js_interop`'s conversion methods. +bool isJSExportedDartFunction(JavaScriptFunction f) { + final function = JS('', '#.#', f, DART_CLOSURE_DART_JSINTEROP_PROPERTY_NAME); + // We set this value so we know it always `is Function`. + return function != null && T == Function ? true : function is T; +} getDispatchProperty(object) { return JS( diff --git a/sdk/lib/_internal/js_runtime/lib/js_allow_interop_patch.dart b/sdk/lib/_internal/js_runtime/lib/js_allow_interop_patch.dart index 27d127bad70..fadaccf47f0 100644 --- a/sdk/lib/_internal/js_runtime/lib/js_allow_interop_patch.dart +++ b/sdk/lib/_internal/js_runtime/lib/js_allow_interop_patch.dart @@ -410,6 +410,11 @@ _callDartFunctionFastN(Function callback, List arguments) { return Function.apply(callback, arguments); } -Function _jsFunctionToDart(JavaScriptFunction f) { - return JS('Function', '#.#', f, DART_CLOSURE_DART_JSINTEROP_PROPERTY_NAME); +T _jsFunctionToDart(JavaScriptFunction f) { + return JS( + 'Function', + '#.#', + f, + DART_CLOSURE_DART_JSINTEROP_PROPERTY_NAME, + ); } diff --git a/sdk/lib/_internal/js_shared/lib/js_interop_patch.dart b/sdk/lib/_internal/js_shared/lib/js_interop_patch.dart index 03b3cac59a1..dba3f79ea94 100644 --- a/sdk/lib/_internal/js_shared/lib/js_interop_patch.dart +++ b/sdk/lib/_internal/js_shared/lib/js_interop_patch.dart @@ -13,6 +13,7 @@ import 'dart:_internal' show patch; import 'dart:_js_helper' show createObjectLiteral, staticInteropGlobalContext; import 'dart:_js_types'; import 'dart:js_interop'; +import 'dart:js_interop_unsafe'; import 'dart:js_util' as js_util; import 'dart:typed_data'; @@ -69,24 +70,25 @@ extension NullableObjectUtilExtension on Object? { // ----------------------------------------------------------------------------- // JSExportedDartFunction <-> Function @patch -extension JSExportedDartFunctionToFunction on JSExportedDartFunction { +extension JSExportedDartFunctionToFunction + on JSExportedDartFunction { @patch - Function get toDart => throw UnimplementedError( + T get toDart => throw UnimplementedError( "'toDart' should never directly be called. Calls to 'toDart' should have " 'been transformed by the interop transformer.', ); } @patch -extension FunctionToJSExportedDartFunction on Function { +extension FunctionToJSExportedDartFunction on T { @patch - JSExportedDartFunction get toJS => throw UnimplementedError( + JSExportedDartFunction get toJS => throw UnimplementedError( "'toJS' should never directly be called. Calls to 'toJS' should have " 'been transformed by the interop transformer.', ); @patch - JSExportedDartFunction get toJSCaptureThis => throw UnimplementedError( + JSExportedDartFunction get toJSCaptureThis => throw UnimplementedError( "'toJSCaptureThis' should never directly be called. Calls to " "'toJSCaptureThis' should have been transformed by the interop " 'transformer.', @@ -136,12 +138,32 @@ bool _isJSObject(Object? any) => bool _isNullableJSObject(Object? any) => any == null || _isJSObject(any); @pragma('dart2js:prefer-inline') -bool _isJSExportedDartFunction(Object? any) => - any is JavaScriptFunction && isJSExportedDartFunction(any); +bool _isJSExportedDartFunction(Object? any) => + any is JavaScriptFunction && isJSExportedDartFunction(any); @pragma('dart2js:prefer-inline') -bool _isNullableJSExportedDartFunction(Object? any) => - any == null || _isJSExportedDartFunction(any); +bool _isNullableJSExportedDartFunction(Object? any) => + any == null || _isJSExportedDartFunction(any); + +// `TypedArray` doesn't exist as a property in JS, but rather as a superclass of +// all typed arrays. In order to do the most sensible thing here, we can use the +// prototype of some typed array type, and check that the receiver is an +// `instanceof` that prototype. See +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray#description +// for more details. + +@JS('Object.getPrototypeOf') +external JSFunction _getPrototypeOf(JSAny o); + +@pragma('dart2js:prefer-inline') +bool _isJSTypedArray(Object? any) { + final typedArrayProto = _getPrototypeOf(globalContext['Int8Array']!); + return _isJSAny(any) && (any as JSAny).instanceof(typedArrayProto); +} + +@pragma('dart2js:prefer-inline') +bool _isNullableJSTypedArray(Object? any) => + any == null || _isJSTypedArray(any); // ----------------------------------------------------------------------------- // JSBoxedDartObject <-> Object diff --git a/sdk/lib/_internal/wasm/lib/js_interop_patch.dart b/sdk/lib/_internal/wasm/lib/js_interop_patch.dart index d7a84344818..3b8761ed059 100644 --- a/sdk/lib/_internal/wasm/lib/js_interop_patch.dart +++ b/sdk/lib/_internal/wasm/lib/js_interop_patch.dart @@ -197,28 +197,29 @@ extension NullableObjectUtilExtension on Object? { // ----------------------------------------------------------------------------- // JSExportedDartFunction <-> Function @patch -extension JSExportedDartFunctionToFunction on JSExportedDartFunction { +extension JSExportedDartFunctionToFunction + on JSExportedDartFunction { @patch - Function get toDart { + T get toDart { final ref = toExternRef; if (!js_helper.isJSWrappedDartFunction(ref)) { throw 'Expected JS wrapped function, but got type ' '${js_helper.typeof(ref)}.'; } - return unwrapJSWrappedDartFunction(ref); + return unwrapJSWrappedDartFunction(ref) as T; } } @patch -extension FunctionToJSExportedDartFunction on Function { +extension FunctionToJSExportedDartFunction on T { @patch - JSExportedDartFunction get toJS => throw UnimplementedError( + JSExportedDartFunction get toJS => throw UnimplementedError( "This should never be called. Calls to 'toJS' should have been " 'transformed by the interop transformer.', ); @patch - JSExportedDartFunction get toJSCaptureThis => throw UnimplementedError( + JSExportedDartFunction get toJSCaptureThis => throw UnimplementedError( "'toJSCaptureThis' should never directly be called. Calls to " "'toJSCaptureThis' should have been transformed by the interop " 'transformer.', @@ -266,12 +267,33 @@ bool _isJSObject(Object? any) => bool _isNullableJSObject(Object? any) => any == null || _isJSObject(any); -bool _isJSExportedDartFunction(Object? any) => - _isJSAny(any) && - js_helper.isJSWrappedDartFunction(unsafeCast(any).toExternRef); +bool _isJSExportedDartFunction(Object? any) { + if (!_isJSAny(any)) return false; + final ref = unsafeCast(any).toExternRef; + if (!js_helper.isJSWrappedDartFunction(ref)) return false; + if (T == Function) return true; + final function = js_helper.unwrapJSWrappedDartFunction(ref); + return function is T; +} -bool _isNullableJSExportedDartFunction(Object? any) => - any == null || _isJSExportedDartFunction(any); +bool _isNullableJSExportedDartFunction(Object? any) => + any == null || _isJSExportedDartFunction(any); + +// `TypedArray` doesn't exist as a property in JS, but rather as a superclass of +// all typed arrays. In order to do the most sensible thing here, we can use the +// prototype of some typed array type, and check that the receiver is an +// `instanceof` that prototype. See +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray#description +// for more details. +bool _isJSTypedArray(Object? any) { + return _isJSAny(any) && + js_helper.JS("""(o) => { + return o instanceof Object.getPrototypeOf(Int8Array); + }""", unsafeCast(any).toExternRef).toBool(); +} + +bool _isNullableJSTypedArray(Object? any) => + any == null || _isJSTypedArray(any); // ----------------------------------------------------------------------------- // JSBoxedDartObject <-> Object diff --git a/sdk/lib/js_interop/js_interop.dart b/sdk/lib/js_interop/js_interop.dart index 483b00e6bb5..0f5d2b6f0c4 100644 --- a/sdk/lib/js_interop/js_interop.dart +++ b/sdk/lib/js_interop/js_interop.dart @@ -221,20 +221,26 @@ external JSObjectType _createObjectLiteral(); /// A JavaScript [`Function`](https://tc39.es/ecma262/#sec-function-objects) /// value. +/// +/// The type parameter [T] is the Dart type signature that corresponds to the +/// signature of the JavaScript function. It is purely descriptive and provides +/// static type checking in Dart, but does not enforce runtime checks on the +/// JavaScript side. @JS('Function') -extension type JSFunction._(JSFunctionType _jsFunction) +extension type JSFunction._(JSFunctionType _jsFunction) implements JSObject, JSFunctionType {} -/// A JavaScript callable function created from a Dart function. +/// A JavaScript function created from a Dart function. +/// +/// The type parameter [T] should be the Dart function's type. /// /// See [FunctionToJSExportedDartFunction.toJS] or /// [FunctionToJSExportedDartFunction.toJSCaptureThis] for more details on how /// to convert a Dart function. @JS('Function') -extension type JSExportedDartFunction._( +extension type JSExportedDartFunction._( JSExportedDartFunctionType _jsExportedDartFunction -) - implements JSFunction, JSExportedDartFunctionType {} +) implements JSFunction, JSExportedDartFunctionType {} /// The synchronous [JS iterable protocol]. /// @@ -462,7 +468,7 @@ extension type JSIteratorResult._(JSObject _) /// A JavaScript [`Array`](https://tc39.es/ecma262/#sec-array-objects). /// /// Because [JSArray] is an extension type, [T] is only a static guarantee and -/// the array does not necessarily only contain [T] elements. For example: +/// the array does not necessarily only contain [T]-typed elements. For example: /// /// ```dart /// @JS() @@ -475,8 +481,8 @@ extension type JSIteratorResult._(JSObject _) /// [T] may introduce additional checking elsewhere, however. When accessing /// elements of [JSArray] with type [T], there is a check to ensure the element /// is a [T] to ensure soundness. Similarly, when converting to a -/// [List], casts may be introduced to ensure that it is indeed -/// a [List]. +/// [List]\, casts may be introduced to ensure that it is +/// indeed a [List]\. @JS('Array') extension type JSArray._(JSArrayType _jsArray) implements JSObject, JSArrayType, JSIterable { @@ -524,11 +530,12 @@ extension type JSArray._(JSArrayType _jsArray) /// A JavaScript `Promise` or a promise-like object. /// /// Because [JSPromise] is an extension type, [T] is only a static guarantee and -/// the [JSPromise] may not actually resolve to a [T]. +/// the [JSPromise] may not actually resolve to a value that is guaranteed to be +/// of type [T] at runtime. /// /// Also like with [JSArray], [T] may introduce additional checking elsewhere. -/// When converted to a [Future], there is a cast to ensure that -/// the [Future] actually resolves to a [T] to ensure soundness. +/// When converted to a [Future]\, the resolved value is cast +/// to [T]. @JS('Promise') extension type JSPromise._(JSPromiseType _jsPromise) implements JSObject, JSPromiseType { @@ -631,8 +638,7 @@ extension type JSUint8Array._(JSUint8ArrayType _jsUint8Array) @JS('Uint8ClampedArray') extension type JSUint8ClampedArray._( JSUint8ClampedArrayType _jsUint8ClampedArray -) - implements JSTypedArray, JSUint8ClampedArrayType { +) implements JSTypedArray, JSUint8ClampedArrayType { /// Creates a JavaScript `Uint8ClampedArray` with [buffer] as its backing /// storage, offset by [byteOffset] bytes, of size [length]. /// @@ -1122,10 +1128,11 @@ extension NullableObjectUtilExtension on Object? { /// - `JSObject`: `isA` will call an intrinsic function to check /// that the value is a JS object (`instanceof Object` is insufficient for /// some objects). - /// - `JSExportedDartFunction`: `isA` will check if + /// - `JSExportedDartFunction`: `isA>` will check if /// the value is a result of a previous /// [FunctionToJSExportedDartFunction.toJS] or - /// [FunctionToJSExportedDartFunction.toJSCaptureThis] call. + /// [FunctionToJSExportedDartFunction.toJSCaptureThis] call and that the + /// Dart function the value forwards to is a function of type `U`. /// - User interop types whose representation types are JS primitive types: /// This will result in an error to avoid confusion on whether the user /// interop type is used in the type-check. Use the primitive JS type as the @@ -1166,46 +1173,49 @@ extension JSFunctionUtilExtension on JSFunction { // Not all Dart types can be converted to JS types and vice versa. // TODO(srujzs): Move some of these to the associated extension type. -/// Conversions from [JSExportedDartFunction] to [Function]. -extension JSExportedDartFunctionToFunction on JSExportedDartFunction { - /// The Dart [Function] that this [JSExportedDartFunction] wrapped. +/// Conversions from [JSExportedDartFunction]\ to [T]. +extension JSExportedDartFunctionToFunction + on JSExportedDartFunction { + /// The Dart function that this [JSExportedDartFunction]\ + /// forwards to. /// - /// Must be a function that was wrapped with + /// Must be a function that was created with /// [FunctionToJSExportedDartFunction.toJS] or /// [FunctionToJSExportedDartFunction.toJSCaptureThis]. - external Function get toDart; + /// + /// The Dart function is cast to [T]. + external T get toDart; } -/// Conversions from [Function] to [JSExportedDartFunction]. -extension FunctionToJSExportedDartFunction on Function { - /// A callable JavaScript function that wraps this [Function]. +/// Conversions from [T] to [JSExportedDartFunction]\. +extension FunctionToJSExportedDartFunction on T { + /// A JavaScript function that forwards to the [T]-typed [Function]. /// - /// If the static type of the [Function] could not be determined or if - /// the static type uses types that are disallowed, the call will fail to - /// compile. See + /// If the type argument to a use of this extension could not be determined at + /// compile-time or if that type contains types that are disallowed, the call + /// will fail to compile. See /// https://dart.dev/interop/js-interop/js-types#requirements-on-external-declarations-and-function-tojs /// for more details on what types are allowed. /// - /// The max number of arguments that are passed to this [Function] from the - /// wrapper JavaScript function is determined by this [Function]'s static - /// type. Any extra arguments passed to the JavaScript function after the max - /// number of arguments are discarded like they are with regular JavaScript - /// functions. + /// The max number of arguments that are passed to this Dart function from the wrapper + /// JavaScript function is determined by this Dart function's static type. Any extra + /// arguments passed to the JavaScript function after the max number of + /// arguments are discarded like they are with regular JavaScript functions. /// /// Calling this on the same [Function] again will always result in a new /// JavaScript function. - external JSExportedDartFunction get toJS; + external JSExportedDartFunction get toJS; - /// A callable JavaScript function that wraps this [Function] and captures the - /// `this` value when called. + /// A JavaScript function that captures the `this` value when called and + /// forwards to the [T]-typed [Function]. /// /// Identical to [toJS], except the resulting [JSExportedDartFunction] will /// pass `this` from JavaScript as the first argument to the converted /// [Function]. Any [Function] that is converted with this member should take /// in an extra parameter at the beginning of the parameter list to handle - /// this. + /// the `this` value. @Since('3.6') - external JSExportedDartFunction get toJSCaptureThis; + external JSExportedDartFunction get toJSCaptureThis; } /// Conversions from [JSBoxedDartObject] to [Object]. @@ -1931,7 +1941,7 @@ extension JSArrayToList on JSArray { /// > conversion will have different semantics. /// /// When compiling to JavaScript, core [List]s are `Array`s and therefore, if - /// the [JSArray] was already a [List] converted via + /// the [JSArray] was already a [List]\ converted via /// [ListToJSArray.toJS], this getter simply casts the `Array`. Otherwise, it /// wraps the `Array` with a [List] that casts the elements to [T] to ensure /// soundness. diff --git a/tests/lib/js/static_interop_test/external_dart_reference_test.dart b/tests/lib/js/static_interop_test/external_dart_reference_test.dart index 88d8ff5c600..5b5bd2311ba 100644 --- a/tests/lib/js/static_interop_test/external_dart_reference_test.dart +++ b/tests/lib/js/static_interop_test/external_dart_reference_test.dart @@ -177,7 +177,12 @@ extension type WritableSignal(JSFunction _) { void set(T value) => _set(value.toExternalReference); - void _update(JSExportedDartFunction update) {} + void _update( + JSExportedDartFunction< + ExternalDartReference Function(ExternalDartReference) + > + update, + ) {} void update(T Function(T) function) { // Because `ExternalDartReference`s are `T` on the JS backends, we can diff --git a/tests/lib/js/static_interop_test/isa/isa_test.dart b/tests/lib/js/static_interop_test/isa/isa_test.dart index 46486a7b7a8..6913d33f7de 100644 --- a/tests/lib/js/static_interop_test/isa/isa_test.dart +++ b/tests/lib/js/static_interop_test/isa/isa_test.dart @@ -106,23 +106,27 @@ void testNull() { Expect.isTrue(nil.isA()); Expect.isTrue(nil.isA()); Expect.isTrue(nil.isA()); - Expect.isTrue(nil.isA()); + Expect.isTrue(nil.isA?>()); + Expect.isTrue(nil.isA()); Expect.isFalse(nil.isA()); Expect.isFalse(nil.isA()); Expect.isFalse(nil.isA()); Expect.isFalse(nil.isA()); - Expect.isFalse(nil.isA()); + Expect.isFalse(nil.isA>()); + Expect.isFalse(nil.isA()); Object? nilObj = null; Expect.isTrue(nilObj.isA()); Expect.isTrue(nilObj.isA()); Expect.isTrue(nilObj.isA()); Expect.isTrue(nilObj.isA()); Expect.isTrue(nilObj.isA()); + Expect.isTrue(nilObj.isA()); Expect.isFalse(nilObj.isA()); Expect.isFalse(nilObj.isA()); Expect.isFalse(nilObj.isA()); Expect.isFalse(nilObj.isA()); Expect.isFalse(nilObj.isA()); + Expect.isFalse(nilObj.isA()); // JS nullish values should behave no differently. eval(''' globalThis.nullable = null; @@ -132,11 +136,13 @@ void testNull() { Expect.isTrue(nullable.isA()); Expect.isTrue(nullable.isA()); Expect.isTrue(nullable.isA()); + Expect.isTrue(nullable.isA()); Expect.isFalse(nullable.isA()); Expect.isFalse(nullable.isA()); Expect.isFalse(nullable.isA()); Expect.isFalse(nullable.isA()); Expect.isFalse(nullable.isA()); + Expect.isFalse(nullable.isA()); eval(''' globalThis.nullable = undefined; '''); @@ -145,11 +151,13 @@ void testNull() { Expect.isTrue(nullable.isA()); Expect.isTrue(nullable.isA()); Expect.isTrue(nullable.isA()); + Expect.isTrue(nullable.isA()); Expect.isFalse(nullable.isA()); Expect.isFalse(nullable.isA()); Expect.isFalse(nullable.isA()); Expect.isFalse(nullable.isA()); Expect.isFalse(nullable.isA()); + Expect.isFalse(nullable.isA()); } void testPrimitives() { @@ -310,19 +318,39 @@ void testJSObjects() { Object jsFunctionObj = jsFunction; Expect.isTrue(jsFunctionObj.isA()); + // The type argument is ignored. + Expect.isTrue(jsFunctionObj.isA>()); Expect.isFalse(jsFunctionObj.isA()); Expect.isFalse(jsFunctionObj.isA()); // JSExportedDartFunction. final jsExportedDartFunction = () {}.toJS; Expect.isTrue(jsExportedDartFunction.isA()); + Expect.isTrue( + jsExportedDartFunction.isA>(), + ); Expect.isTrue(jsExportedDartFunction.isA()); + Expect.isTrue( + jsExportedDartFunction.isA?>(), + ); + Expect.isFalse( + jsExportedDartFunction.isA>(), + ); + Expect.isFalse( + jsExportedDartFunction.isA?>(), + ); Expect.isTrue(jsExportedDartFunction.isA()); testIsJSObject(jsExportedDartFunction); Expect.isFalse(jsExportedDartFunction.isA()); Object? jsExportedDartFunctionObj = jsExportedDartFunction; Expect.isTrue(jsExportedDartFunctionObj.isA()); + Expect.isTrue( + jsExportedDartFunctionObj.isA>(), + ); + Expect.isFalse( + jsExportedDartFunction.isA?>(), + ); Expect.isTrue(jsExportedDartFunctionObj.isA()); Expect.isFalse(jsExportedDartFunctionObj.isA()); } diff --git a/tests/lib/js/static_interop_test/js_types_static_errors_test.dart b/tests/lib/js/static_interop_test/js_types_static_errors_test.dart index 100c30dbbc2..4b5c1433d76 100644 --- a/tests/lib/js/static_interop_test/js_types_static_errors_test.dart +++ b/tests/lib/js/static_interop_test/js_types_static_errors_test.dart @@ -31,14 +31,14 @@ void main() { // ^^^^^^^^^^^^^^^^^ // [analyzer] COMPILE_TIME_ERROR.ARGUMENT_TYPE_NOT_ASSIGNABLE // ^ - // [web] The argument type 'Function' can't be assigned to the parameter type 'JSFunction'. + // [web] The argument type 'Function' can't be assigned to the parameter type 'JSFunction'. // [JSExportedDartFunction] != [Function] ((JSExportedDartFunction jsFun) {})(() {} as Function); // ^^^^^^^^^^^^^^^^^ // [analyzer] COMPILE_TIME_ERROR.ARGUMENT_TYPE_NOT_ASSIGNABLE // ^ - // [web] The argument type 'Function' can't be assigned to the parameter type 'JSExportedDartFunction'. + // [web] The argument type 'Function' can't be assigned to the parameter type 'JSExportedDartFunction'. // [JSBoxedDartObject] != [Object] ((JSBoxedDartObject jsObj) {})(DartObject()); diff --git a/tests/lib/js/static_interop_test/js_types_test.dart b/tests/lib/js/static_interop_test/js_types_test.dart index 6945cf0fc7e..56a670e4cc6 100644 --- a/tests/lib/js/static_interop_test/js_types_test.dart +++ b/tests/lib/js/static_interop_test/js_types_test.dart @@ -42,7 +42,11 @@ external JSFunction fun; external JSString doFun(JSString a, JSString b); @JS() -external JSExportedDartFunction edf; +external JSExportedDartFunction edf; + +@JS() +external JSExportedDartFunction +edfWithThis; @JS() external JSArray arr; @@ -196,17 +200,20 @@ void syncTests() { return (a.toDart + b.toDart).toJS; }; edf = dartFunction.toJS; + // Should be able to assign to `JSFunction`. + JSFunction _ = edf; Expect.equals('foobar', doFun('foo'.toJS, 'bar'.toJS).toDart); - Expect.equals( - 'foobar', - (edf.toDart as JSString Function(JSString, JSString))( - 'foo'.toJS, - 'bar'.toJS, - ).toDart, - ); + Expect.equals('foobar', edf.toDart('foo'.toJS, 'bar'.toJS).toDart); Expect.identical(edf.toDart, dartFunction); + // `toDart` with just `Function` should succeed. + Expect.identical( + (edf as JSExportedDartFunction).toDart, + dartFunction, + ); // Two wrappers should not be the same. Expect.notEquals(edf, dartFunction.toJS); + // If the wrong function type, `toDart` should throw. + Expect.throws(() => (edf as JSExportedDartFunction).toDart); // Converting a non-function should throw. Expect.throws(() => ('foo'.toJS as JSExportedDartFunction).toDart); // `this` should be captured correctly in `toJSCaptureThis`. @@ -215,13 +222,22 @@ void syncTests() { Expect.equals(this_, this__); return (a.toDart + b.toDart).toJS; }; - edf = dartFunctionThis.toJSCaptureThis; + edfWithThis = dartFunctionThis.toJSCaptureThis; Expect.equals( - (edf.callAsFunction(this_, 'foo'.toJS, 'bar'.toJS) as JSString).toDart, + (edfWithThis.callAsFunction(this_, 'foo'.toJS, 'bar'.toJS) as JSString) + .toDart, 'foobar', ); - Expect.identical(edf.toDart, dartFunctionThis); - Expect.notEquals(edf, dartFunctionThis.toJSCaptureThis); + Expect.identical(edfWithThis.toDart, dartFunctionThis); + Expect.identical( + (edfWithThis as JSExportedDartFunction).toDart, + dartFunctionThis, + ); + Expect.throws( + () => + (edfWithThis as JSExportedDartFunction).toDart, + ); + Expect.notEquals(edfWithThis, dartFunctionThis.toJSCaptureThis); // [JSIterable] final iterable = JSSet([1.toJS, 2.toJS].toJS);