-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Closed
Labels
area-core-librarySDK core library issues (core, async, ...); use area-vm or area-web for platform specific libraries.SDK core library issues (core, async, ...); use area-vm or area-web for platform specific libraries.library-asynctype-bugIncorrect behavior (everything from a crash to more subtle misbehavior)Incorrect behavior (everything from a crash to more subtle misbehavior)
Description
This example throws:
void main() async {
final future = Future<void>.delayed(
Duration(seconds: 1),
() => throw Exception(),
);
future.whenComplete(() async {
print('whenComplete()');
await Future.delayed(Duration.zero); // This line prevents the silencing.
}).ignore();
}% dart main.dart
whenComplete()
Unhandled exception:
Exception
#0 main.<anonymous closure> (package:my_package/main.dart:4:11)
#1 new Future.delayed.<anonymous closure> (dart:async/future.dart:431:42)
#2 Timer._createTimer.<anonymous closure> (dart:async-patch/timer_patch.dart:18:15)
#3 _Timer._runTimers (dart:isolate-patch/timer_impl.dart:398:19)
#4 _Timer._handleMessage (dart:isolate-patch/timer_impl.dart:429:5)
#5 _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:184:12)
However, if the asynchronous gap is removed from the callback, the error is ignored as expected:
void main() async {
final future = Future<void>.delayed(
Duration(seconds: 1),
() => throw Exception(),
);
future.whenComplete(() async {
print('whenComplete()'); // No gap.
}).ignore();
await Future.delayed(Duration(seconds: 1));
}% dart main.dart
whenComplete()
I consider this a bug because this behaviour contradicts the doc of whenComplete method which says it's equivalent to the following:
Future<T> whenComplete(action()) {
return this.then((v) {
var f2 = action();
if (f2 is Future) return f2.then((_) => v);
return v;
}, onError: (e) {
var f2 = action();
if (f2 is Future) return f2.then((_) { throw e; });
throw e;
});
}When using this equivalent, ignore() successfully silences the error even with an asynchronous gap in the callback:
void main() async {
final future = Future<void>.delayed(
Duration(seconds: 1),
() => throw Exception(),
);
future.whenCompleteEquivalent(() async {
print('whenComplete()');
await Future.delayed(Duration.zero);
}).ignore();
}
extension FutureExtension<T> on Future<T> {
Future<T> whenCompleteEquivalent(action()) {
return this.then((v) {
var f2 = action();
if (f2 is Future) return f2.then((_) => v);
return v;
}, onError: (e) {
var f2 = action();
if (f2 is Future) return f2.then((_) {
throw e;
});
throw e;
});
}
}% dart main.dart
whenComplete()
Also, it just feels wrong. When passing a callback to whenComplete(), it's impossible to tell if it has an asynchronous gap, and untestable things should not be such a strong factor in a deterministic API like this one.
I can reproduce this in both stable and dev.
dart info (3.5.3 stable)
If providing this information as part of reporting a bug, please review the information
below to ensure it only contains things you're comfortable posting publicly.
#### General info
- Dart 3.5.3 (stable) (Wed Sep 11 16:22:47 2024 +0000) on "macos_arm64"
- on macos / Version 13.6 (Build 22G120)
- locale is es-GE
#### Process info
| Memory | CPU | Elapsed time | Command line |
| -----: | ---: | -----------: | ------------------------------------------------------------------------------------------ |
| 28 MB | 0.0% | 03-07:03:12 | dart devtools --machine --dtd-uri=ws:<path>/XEjeVjO68XdEYq9P |
| 28 MB | 0.0% | 03-05:45:11 | dart devtools --machine --dtd-uri=ws:<path>/s7qnnoiffl3kKD12 |
| 24 MB | 0.0% | 04-01:24:03 | dart devtools --machine --dtd-uri=ws:<path>/tYaTy5CYayArivx6 |
| 28 MB | 0.0% | 03-06:54:10 | dart devtools --machine --dtd-uri=ws:<path>/x4l4KEhjBLqhKJCY |
| 155 MB | 0.0% | 04-01:24:03 | dart language-server --client-id=Android-Studio --client-version=AI-241.15989.150 --protocol=analyzer |
| 366 MB | 0.0% | 03-07:03:14 | dart language-server --client-id=Android-Studio --client-version=AI-241.15989.150 --protocol=analyzer |
| 299 MB | 0.0% | 03-06:54:12 | dart language-server --client-id=Android-Studio --client-version=AI-241.15989.150 --protocol=analyzer |
| 506 MB | 0.0% | 03-05:45:12 | dart language-server --client-id=Android-Studio --client-version=AI-241.15989.150 --protocol=analyzer |
| 27 MB | 0.0% | 04-01:24:03 | dart tooling-daemon --machine |
| 29 MB | 0.0% | 03-07:03:12 | dart tooling-daemon --machine |
| 29 MB | 0.0% | 03-06:54:11 | dart tooling-daemon --machine |
| 29 MB | 0.0% | 03-05:45:11 | dart tooling-daemon --machine |
| 47 MB | 0.0% | 04-01:24:08 | flutter_tools.snapshot daemon |
| 47 MB | 0.0% | 03-07:03:17 | flutter_tools.snapshot daemon |
| 47 MB | 0.0% | 03-06:54:12 | flutter_tools.snapshot daemon |
| 47 MB | 0.0% | 03-05:45:12 | flutter_tools.snapshot daemon |
dart info (3.6.0-277.0.dev)
If providing this information as part of reporting a bug, please review the information
below to ensure it only contains things you're comfortable posting publicly.
#### General info
- Dart 3.6.0-277.0.dev (dev) (Tue Sep 24 21:06:37 2024 -0700) on "macos_arm64"
- on macos / Version 13.6 (Build 22G120)
- locale is es-GE
#### Process info
| Memory | CPU | Elapsed time | Command line |
| -----: | ---: | -----------: | ------------------------------------------------------------------------------------------ |
| 28 MB | 0.0% | 03-07:04:51 | dart devtools --machine --dtd-uri=ws:<path>/XEjeVjO68XdEYq9P |
| 28 MB | 0.0% | 03-05:46:50 | dart devtools --machine --dtd-uri=ws:<path>/s7qnnoiffl3kKD12 |
| 24 MB | 0.0% | 04-01:25:42 | dart devtools --machine --dtd-uri=ws:<path>/tYaTy5CYayArivx6 |
| 28 MB | 0.0% | 03-06:55:49 | dart devtools --machine --dtd-uri=ws:<path>/x4l4KEhjBLqhKJCY |
| 155 MB | 0.0% | 04-01:25:42 | dart language-server --client-id=Android-Studio --client-version=AI-241.15989.150 --protocol=analyzer |
| 366 MB | 0.0% | 03-07:04:53 | dart language-server --client-id=Android-Studio --client-version=AI-241.15989.150 --protocol=analyzer |
| 299 MB | 0.0% | 03-06:55:51 | dart language-server --client-id=Android-Studio --client-version=AI-241.15989.150 --protocol=analyzer |
| 506 MB | 0.0% | 03-05:46:51 | dart language-server --client-id=Android-Studio --client-version=AI-241.15989.150 --protocol=analyzer |
| 27 MB | 0.0% | 04-01:25:42 | dart tooling-daemon --machine |
| 29 MB | 0.0% | 03-07:04:51 | dart tooling-daemon --machine |
| 29 MB | 0.0% | 03-06:55:50 | dart tooling-daemon --machine |
| 29 MB | 0.0% | 03-05:46:50 | dart tooling-daemon --machine |
| 47 MB | 0.0% | 04-01:25:47 | flutter_tools.snapshot daemon |
| 47 MB | 0.0% | 03-07:04:56 | flutter_tools.snapshot daemon |
| 47 MB | 0.0% | 03-06:55:51 | flutter_tools.snapshot daemon |
| 47 MB | 0.0% | 03-05:46:51 | flutter_tools.snapshot daemon |
Metadata
Metadata
Assignees
Labels
area-core-librarySDK core library issues (core, async, ...); use area-vm or area-web for platform specific libraries.SDK core library issues (core, async, ...); use area-vm or area-web for platform specific libraries.library-asynctype-bugIncorrect behavior (everything from a crash to more subtle misbehavior)Incorrect behavior (everything from a crash to more subtle misbehavior)