diff --git a/pkg/_js_interop_checks/lib/src/transformations/js_util_wasm_optimizer.dart b/pkg/_js_interop_checks/lib/src/transformations/js_util_wasm_optimizer.dart index 1e7169f29fa..b7287a5fed4 100644 --- a/pkg/_js_interop_checks/lib/src/transformations/js_util_wasm_optimizer.dart +++ b/pkg/_js_interop_checks/lib/src/transformations/js_util_wasm_optimizer.dart @@ -274,6 +274,9 @@ class JsUtilWasmOptimizer extends Transformer { callbackTarget.function.positionalParameters[i].initializer; } else if (argument is FunctionExpression) { initializer = argument.function.positionalParameters[i].initializer; + } else if (argument is InstanceTearOff) { + initializer = argument.interfaceTargetReference.asProcedure.function + .positionalParameters[i].initializer; } else { throw 'Cannot pass default arguments.'; } diff --git a/tests/web/wasm/callback_test.dart b/tests/web/wasm/callback_test.dart index 24d35d371e4..34cc0317f62 100644 --- a/tests/web/wasm/callback_test.dart +++ b/tests/web/wasm/callback_test.dart @@ -155,6 +155,30 @@ void staticInteropCallbackTest() { Expect.equals('foobar', helper.doSumTwoOptionalCNonNull('foo', 'bar')); } +typedef NoArgsFun = String Function(); +typedef OneArgFun = String Function(String arg); +typedef OnePositionalAndOneOptionalArgsFun = String Function(String arg, + [String arg2]); +typedef TwoPositionalArgsFun = String Function([String arg, String arg2]); + +class TornOffClass { + String noArgs() { + return 'foo'; + } + + String oneArg(String arg) { + return arg; + } + + String onePositionalAndOneOptionalArgs(String arg, [String arg2 = 'bar']) { + return arg + arg2; + } + + String twoPositionalArgs([String arg = 'foo', String? arg2]) { + return arg + (arg2 ?? ''); + } +} + void allowInteropCallbackTest() { eval(r''' globalThis.doSum1 = function(summer) { @@ -193,6 +217,26 @@ void allowInteropCallbackTest() { globalThis.doSumTwoOptionalCNonNull = function(a, b) { return summer(a, b); } + + // tear off cases + globalThis.tearOffNoArgs = function (f) { + return f(); + } + globalThis.tearOffOneArg = function (f) { + return f('foo'); + } + globalThis.tearOffOnePositionalAndOneOptionalArgsA = function (f) { + return f('foo'); + } + globalThis.tearOffOnePositionalAndOneOptionalArgsB = function (f) { + return f('foo', 'baz'); + } + globalThis.tearOffTwoPositionalArgsA = function (f) { + return f('foo'); + } + globalThis.tearOffTwoPositionalArgsB = function (f) { + return f('foo', 'baz'); + } '''); // General @@ -266,6 +310,63 @@ void allowInteropCallbackTest() { Expect.equals('foobar', callMethod(globalThis, 'doSumTwoOptionalC', ['foo', 'bar']).toString()); } + + // Tear off cases + // No args. + { + final t = TornOffClass(); + final interopCallback = allowInterop(t.noArgs); + Expect.equals( + 'foo', callMethod(globalThis, 'tearOffNoArgs', [interopCallback])); + } + + // One arg. + { + final t = TornOffClass(); + final interopCallback = allowInterop(t.oneArg); + Expect.equals( + 'foo', callMethod(globalThis, 'tearOffOneArg', [interopCallback])); + } + + // One positional and one optional case A. + { + final t = TornOffClass(); + final interopCallback = allowInterop( + t.onePositionalAndOneOptionalArgs); + Expect.equals( + 'foobar', + callMethod(globalThis, 'tearOffOnePositionalAndOneOptionalArgsA', + [interopCallback])); + } + + // One positional and one optional case B. + { + final t = TornOffClass(); + final interopCallback = allowInterop( + t.onePositionalAndOneOptionalArgs); + Expect.equals( + 'foobaz', + callMethod(globalThis, 'tearOffOnePositionalAndOneOptionalArgsB', + [interopCallback])); + } + + // Two positional case A. + { + final t = TornOffClass(); + final interopCallback = + allowInterop(t.twoPositionalArgs); + Expect.equals('foo', + callMethod(globalThis, 'tearOffTwoPositionalArgsA', [interopCallback])); + } + + // Two positional case B. + { + final t = TornOffClass(); + final interopCallback = + allowInterop(t.twoPositionalArgs); + Expect.equals('foobaz', + callMethod(globalThis, 'tearOffTwoPositionalArgsB', [interopCallback])); + } } void main() {