Description
Currently the following code throws an uncatchable syntax error:
import 'dart:async';
void badFn() {continue;}
void main() {
runZoned(() => badFn(), onError: (error, stackTrace) {
print("caught error");
});
}
This doesn't print "caught error", but instead kills the isolate due to the error. However, the error is only thrown at runtime, as can be seen with this modification:
void badFn() {continue;}
void main(List<String> args) {
if (args.isNotEmpty) badFn();
}
This only throws a syntax error if an argument is passed on the command line. Moreover, the error is recoverable; for example:
// inner.dart
import 'dart:async';
void badFn() {continue;}
void main(List<String> args) {
new Future(() => badFn());
badFn();
}
// outer.dart
import 'dart:isolate';
main() async {
var isolate = await Isolate.spawnUri(
Uri.parse("inner.dart"), [], null, paused: true);
isolate.setErrorsFatal(false);
var receivePort = new ReceivePort();
isolate.addErrorListener(receivePort.sendPort);
isolate.resume(isolate.pauseCapability);
receivePort.listen((error) => print(error.first));
}
Running outer.dart
will produce two errors, so clearly there's a way to keep the isolate running and even keep badFn
callable despite this syntax error.
This is important for use cases like the test runner, where user code is loaded and specific functions are run. Error reporting should be associated with the functions that cause the errors, but they can only be captured globally and there's no way to link them back to the actual function that failed.
This also means that the user can't be confident that running an arbitrary function in an error zone will capture any errors that function might produce. This is useful even when not loading code dynamically; for example, an application may want to have a global error handler for itself that shows an error-reporting dialog.
Activity