From 757d806b36e21be33c54a0683a66f69b36b4da41 Mon Sep 17 00:00:00 2001 From: Lasse Reichstein Holst Nielsen Date: Mon, 4 Dec 2017 07:11:44 +0000 Subject: [PATCH] Add type parameter to Isolate.spawn. This is a strong mode migration that was missed in the earlier rounds. It allows use of functions that have a more restricted argument type than Object in strong mode while still ensuring that the argument has a correct type. Change-Id: Ib00e3f4b4a679c003a992d674c36ef672729b22e Reviewed-on: https://dart-review.googlesource.com/24540 Commit-Queue: Lasse R.H. Nielsen Reviewed-by: Leaf Petersen --- CHANGELOG.md | 3 + .../tool/input_sdk/patch/isolate_patch.dart | 9 +-- .../input_sdk/private/isolate_helper.dart | 2 +- runtime/lib/isolate_patch.dart | 2 +- .../js_runtime/lib/isolate_helper.dart | 2 +- .../js_runtime/lib/isolate_patch.dart | 4 +- sdk/lib/core/uri.dart | 20 +++---- sdk/lib/isolate/isolate.dart | 3 +- tests/lib_2/isolate/spawn_generic_test.dart | 60 +++++++++++++++++++ tests/lib_2/lib_2_kernel.status | 6 -- .../spawn_function_root_library_test.dart | 2 +- 11 files changed, 82 insertions(+), 31 deletions(-) create mode 100644 tests/lib_2/isolate/spawn_generic_test.dart diff --git a/CHANGELOG.md b/CHANGELOG.md index 99d74b0c778..2db006c98c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -88,6 +88,9 @@ * `dart:isolate` * Rename `IMMEDIATE` and `BEFORE_NEXT_EVENT` on `Isolate` to `immediate` and `beforeNextEvent`. + * Make `Isolate.spawn` take a type parameter representing the argument type + of the provided function. This allows functions with arguments types other + than `Object` in strong mode. * `dart.math` * Renamed `E`, `LN10`, `LN`, `LOG2E`, `LOG10E`, `PI`, `SQRT1_2` and `SQRT2` diff --git a/pkg/dev_compiler/tool/input_sdk/patch/isolate_patch.dart b/pkg/dev_compiler/tool/input_sdk/patch/isolate_patch.dart index b00c1d89bcd..07293e603ee 100644 --- a/pkg/dev_compiler/tool/input_sdk/patch/isolate_patch.dart +++ b/pkg/dev_compiler/tool/input_sdk/patch/isolate_patch.dart @@ -8,8 +8,6 @@ import 'dart:_js_helper' show patch; import 'dart:_isolate_helper' show CapabilityImpl, IsolateNatives, ReceivePortImpl, RawReceivePortImpl; -typedef _UnaryFunction(arg); - @patch class Isolate { static final _currentIsolateCache = IsolateNatives.currentIsolate; @@ -38,7 +36,7 @@ class Isolate { } @patch - static Future spawn(void entryPoint(message), var message, + static Future spawn(void entryPoint(T message), T message, {bool paused: false, bool errorsAreFatal, SendPort onExit, @@ -46,11 +44,6 @@ class Isolate { bool forcePause = (errorsAreFatal != null) || (onExit != null) || (onError != null); try { - // Check for the type of `entryPoint` on the spawning isolate to make - // error-handling easier. - if (entryPoint is! _UnaryFunction) { - throw new ArgumentError(entryPoint); - } // TODO: Consider passing the errorsAreFatal/onExit/onError values // as arguments to the internal spawnUri instead of setting // them after the isolate has been created. diff --git a/pkg/dev_compiler/tool/input_sdk/private/isolate_helper.dart b/pkg/dev_compiler/tool/input_sdk/private/isolate_helper.dart index e75af52f45d..20941a0ff7d 100644 --- a/pkg/dev_compiler/tool/input_sdk/private/isolate_helper.dart +++ b/pkg/dev_compiler/tool/input_sdk/private/isolate_helper.dart @@ -936,7 +936,7 @@ class IsolateNatives { } static Future spawnFunction( - void topLevelFunction(message), var message, bool startPaused) { + void topLevelFunction(Null message), var message, bool startPaused) { IsolateNatives.enableSpawnWorker = true; final name = _getJSFunctionName(topLevelFunction); if (name == null) { diff --git a/runtime/lib/isolate_patch.dart b/runtime/lib/isolate_patch.dart index 26d3b2ff53d..99cb61b1374 100644 --- a/runtime/lib/isolate_patch.dart +++ b/runtime/lib/isolate_patch.dart @@ -325,7 +325,7 @@ class Isolate { (VMLibraryHooks.resolvePackageUriFuture != null); @patch - static Future spawn(void entryPoint(message), var message, + static Future spawn(void entryPoint(T message), T message, {bool paused: false, bool errorsAreFatal, SendPort onExit, diff --git a/sdk/lib/_internal/js_runtime/lib/isolate_helper.dart b/sdk/lib/_internal/js_runtime/lib/isolate_helper.dart index e9de3d7101a..f4d83d91fce 100644 --- a/sdk/lib/_internal/js_runtime/lib/isolate_helper.dart +++ b/sdk/lib/_internal/js_runtime/lib/isolate_helper.dart @@ -949,7 +949,7 @@ class IsolateNatives { } static Future spawnFunction( - void topLevelFunction(message), var message, bool startPaused) { + void topLevelFunction(Null message), var message, bool startPaused) { IsolateNatives.enableSpawnWorker = true; final name = _getJSFunctionName(topLevelFunction); if (name == null) { diff --git a/sdk/lib/_internal/js_runtime/lib/isolate_patch.dart b/sdk/lib/_internal/js_runtime/lib/isolate_patch.dart index 5d3da78eb42..9b46ac24bf8 100644 --- a/sdk/lib/_internal/js_runtime/lib/isolate_patch.dart +++ b/sdk/lib/_internal/js_runtime/lib/isolate_patch.dart @@ -8,7 +8,7 @@ import 'dart:_js_helper' show patch; import 'dart:_isolate_helper' show CapabilityImpl, IsolateNatives, ReceivePortImpl, RawReceivePortImpl; -typedef _UnaryFunction(arg); +typedef _UnaryFunction(Null arg); @patch class Isolate { @@ -41,7 +41,7 @@ class Isolate { } @patch - static Future spawn(void entryPoint(message), var message, + static Future spawn(void entryPoint(T message), T message, {bool paused: false, bool errorsAreFatal, SendPort onExit, diff --git a/sdk/lib/core/uri.dart b/sdk/lib/core/uri.dart index d03f6d8d10a..dd4fe118689 100644 --- a/sdk/lib/core/uri.dart +++ b/sdk/lib/core/uri.dart @@ -2848,7 +2848,7 @@ class _Uri implements Uri { // be escaped or not. // The unreserved characters of RFC 3986. - static const _unreservedTable = const [ + static const _unreservedTable = const [ // LSB MSB // | | 0x0000, // 0x00 - 0x0f 0000000000000000 @@ -2868,7 +2868,7 @@ class _Uri implements Uri { ]; // The unreserved characters of RFC 2396. - static const _unreserved2396Table = const [ + static const _unreserved2396Table = const [ // LSB MSB // | | 0x0000, // 0x00 - 0x0f 0000000000000000 @@ -2888,7 +2888,7 @@ class _Uri implements Uri { ]; // Table of reserved characters specified by ECMAScript 5. - static const _encodeFullTable = const [ + static const _encodeFullTable = const [ // LSB MSB // | | 0x0000, // 0x00 - 0x0f 0000000000000000 @@ -2908,7 +2908,7 @@ class _Uri implements Uri { ]; // Characters allowed in the scheme. - static const _schemeTable = const [ + static const _schemeTable = const [ // LSB MSB // | | 0x0000, // 0x00 - 0x0f 0000000000000000 @@ -2928,7 +2928,7 @@ class _Uri implements Uri { ]; // Characters allowed in scheme except for upper case letters. - static const _schemeLowerTable = const [ + static const _schemeLowerTable = const [ // LSB MSB // | | 0x0000, // 0x00 - 0x0f 0000000000000000 @@ -2952,7 +2952,7 @@ class _Uri implements Uri { // / "*" / "+" / "," / ";" / "=" // RFC 3986 section 2.3. // unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" - static const _subDelimitersTable = const [ + static const _subDelimitersTable = const [ // LSB MSB // | | 0x0000, // 0x00 - 0x0f 0000000000000000 @@ -2974,7 +2974,7 @@ class _Uri implements Uri { // General delimiter characters, RFC 3986 section 2.2. // gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@" // - static const _genDelimitersTable = const [ + static const _genDelimitersTable = const [ // LSB MSB // | | 0x0000, // 0x00 - 0x0f 0000000000000000 @@ -2996,7 +2996,7 @@ class _Uri implements Uri { // Characters allowed in the userinfo as of RFC 3986. // RFC 3986 Appendix A // userinfo = *( unreserved / pct-encoded / sub-delims / ':') - static const _userinfoTable = const [ + static const _userinfoTable = const [ // LSB MSB // | | 0x0000, // 0x00 - 0x0f 0000000000000000 @@ -3018,7 +3018,7 @@ class _Uri implements Uri { // Characters allowed in the reg-name as of RFC 3986. // RFC 3986 Appendix A // reg-name = *( unreserved / pct-encoded / sub-delims ) - static const _regNameTable = const [ + static const _regNameTable = const [ // LSB MSB // | | 0x0000, // 0x00 - 0x0f 0000000000000000 @@ -3040,7 +3040,7 @@ class _Uri implements Uri { // Characters allowed in the path as of RFC 3986. // RFC 3986 section 3.3. // pchar = unreserved / pct-encoded / sub-delims / ":" / "@" - static const _pathCharTable = const [ + static const _pathCharTable = const [ // LSB MSB // | | 0x0000, // 0x00 - 0x0f 0000000000000000 diff --git a/sdk/lib/isolate/isolate.dart b/sdk/lib/isolate/isolate.dart index 20ff5be6c56..734204a287a 100644 --- a/sdk/lib/isolate/isolate.dart +++ b/sdk/lib/isolate/isolate.dart @@ -228,7 +228,8 @@ class Isolate { * Returns a future which will complete with an [Isolate] instance if the * spawning succeeded. It will complete with an error otherwise. */ - external static Future spawn(void entryPoint(message), var message, + external static Future spawn( + void entryPoint(T message), T message, {bool paused: false, bool errorsAreFatal, SendPort onExit, diff --git a/tests/lib_2/isolate/spawn_generic_test.dart b/tests/lib_2/isolate/spawn_generic_test.dart new file mode 100644 index 00000000000..203f8553d6a --- /dev/null +++ b/tests/lib_2/isolate/spawn_generic_test.dart @@ -0,0 +1,60 @@ +// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +// Check that Isolate.spawn is generic. +library spawn_generic; + +import "dart:isolate"; +import "dart:async"; +import "package:async_helper/async_helper.dart"; +import "package:expect/expect.dart"; + +void isomain(num args) { + print(args); + // All is well. No throwing. +} + +int _count = 0; +void enter() { + asyncStart(); + _count++; +} + +bool exit() { + asyncEnd(); + return --_count == 0; +} + +main() { + var remotePort = new RawReceivePort(); + remotePort.handler = (m) { + if (m == null) { + if (exit()) remotePort.close(); + } else { + List list = m; + throw new AsyncError(m[0], new StackTrace.fromString(m[1])); + } + }; + var port = remotePort.sendPort; + + // Explicit type works. + enter(); + Isolate.spawn(isomain, 42, onExit: port, onError: port); + enter(); + Isolate.spawn(isomain, 42, onExit: port, onError: port); + enter(); + Isolate.spawn(isomain, 1.2, onExit: port, onError: port); + enter(); + Isolate.spawn(isomain, 1.2, onExit: port, onError: port); + enter(); + Isolate.spawn(isomain, null, onExit: port, onError: port); + + // Inference gets it right. + enter(); + Isolate.spawn(isomain, 42, onExit: port, onError: port); + enter(); + Isolate.spawn(isomain, 1.2, onExit: port, onError: port); + enter(); + Isolate.spawn(isomain, null, onExit: port, onError: port); +} diff --git a/tests/lib_2/lib_2_kernel.status b/tests/lib_2/lib_2_kernel.status index 4a5aa423c51..151aef40420 100644 --- a/tests/lib_2/lib_2_kernel.status +++ b/tests/lib_2/lib_2_kernel.status @@ -308,7 +308,6 @@ convert/json_toEncodable_reviver_test: CompileTimeError convert/json_utf8_chunk_test: RuntimeError convert/streamed_conversion_json_encode1_test: RuntimeError convert/streamed_conversion_json_utf8_encode_test: RuntimeError -isolate/compile_time_error_test/none: RuntimeError isolate/count_test: Timeout isolate/cross_isolate_message_test: RuntimeError isolate/illegal_msg_function_test: RuntimeError @@ -333,19 +332,15 @@ isolate/message_test: RuntimeError isolate/mint_maker_test: RuntimeError isolate/nested_spawn2_test: RuntimeError isolate/nested_spawn_test: Timeout -isolate/ondone_test: RuntimeError isolate/ping_pause_test: RuntimeError isolate/raw_port_test: RuntimeError isolate/request_reply_test: Timeout -isolate/simple_message_test/none: RuntimeError isolate/spawn_function_test: Timeout -isolate/spawn_uri_missing_from_isolate_test: RuntimeError isolate/spawn_uri_multi_test/none: RuntimeError isolate/spawn_uri_nested_vm_test: RuntimeError isolate/spawn_uri_test: RuntimeError isolate/spawn_uri_vm_test: RuntimeError isolate/stacktrace_message_test: RuntimeError -isolate/start_paused_test: RuntimeError isolate/static_function_test: Timeout isolate/timer_isolate_test: RuntimeError isolate/typed_message_test: RuntimeError @@ -397,7 +392,6 @@ mirrors/reflected_type_test/03: MissingCompileTimeError mirrors/regress_16321_test/none: Crash mirrors/regress_19731_test: RuntimeError mirrors/return_type_test: RuntimeError -mirrors/spawn_function_root_library_test: RuntimeError mirrors/top_level_accessors_test/01: MissingCompileTimeError mirrors/type_argument_is_type_variable_test: RuntimeError mirrors/typearguments_mirror_test: RuntimeError diff --git a/tests/lib_2/mirrors/spawn_function_root_library_test.dart b/tests/lib_2/mirrors/spawn_function_root_library_test.dart index 158704e68a6..5f06c62c6eb 100644 --- a/tests/lib_2/mirrors/spawn_function_root_library_test.dart +++ b/tests/lib_2/mirrors/spawn_function_root_library_test.dart @@ -16,7 +16,7 @@ child(SendPort port) { } main() { - var port; + RawReceivePort port; port = new RawReceivePort((String childRootUri) { LibraryMirror root = currentMirrorSystem().isolate.rootLibrary; Expect.isNotNull(root);