Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 9200023

Browse files
lrhnCommit Queue
authored and
Commit Queue
committed
Use AsyncError more in future error handling.
Avoids some cases of calling `Zone.errorCallback` and getting an `AsyncError`, then unpacking it again to separate errors and stack trace objects. CoreLibraryReviewExempt: No API changes, no platform-specific code change. Change-Id: I903dbfa6da74cfdf8f00e765e48311cc0cb40cac Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/405022 Commit-Queue: Lasse Nielsen <lrn@google.com> Reviewed-by: Nate Bosch <nbosch@google.com>
1 parent 7566327 commit 9200023

File tree

5 files changed

+123
-133
lines changed

5 files changed

+123
-133
lines changed

‎sdk/lib/_internal/js_dev_runtime/patch/async_patch.dart‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ _async<T>(Function() initGenerator) {
127127
if (isRunningAsEvent) {
128128
_completeWithErrorCallback(asyncFuture, e, s);
129129
} else {
130-
_asyncCompleteWithErrorCallback(asyncFuture, e, s);
130+
asyncFuture._asyncCompleteErrorObject(_interceptCaughtError(e, s));
131131
}
132132
}
133133
}

‎sdk/lib/async/future.dart‎

Lines changed: 15 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -314,9 +314,8 @@ abstract interface class Future<T> {
314314
try {
315315
result = computation();
316316
} catch (error, stackTrace) {
317-
var future = new _Future<T>();
318-
_asyncCompleteWithErrorCallback(future, error, stackTrace);
319-
return future;
317+
return _Future<T>()
318+
.._asyncCompleteErrorObject(_interceptCaughtError(error, stackTrace));
320319
}
321320
return result is Future<T> ? result : _Future<T>.value(result);
322321
}
@@ -369,10 +368,8 @@ abstract interface class Future<T> {
369368
///
370369
/// final error = await getFuture(); // Throws.
371370
/// ```
372-
factory Future.error(Object error, [StackTrace? stackTrace]) {
373-
AsyncError(:error, :stackTrace) = _interceptUserError(error, stackTrace);
374-
return new _Future<T>.immediateError(error, stackTrace);
375-
}
371+
factory Future.error(Object error, [StackTrace? stackTrace]) =>
372+
_Future<T>.immediateError(_interceptUserError(error, stackTrace));
376373

377374
/// Creates a future that runs its computation after a delay.
378375
///
@@ -561,25 +558,21 @@ abstract interface class Future<T> {
561558
return _future.._completeWithValue(<T>[]);
562559
}
563560
values = List<T?>.filled(remaining, null);
564-
} catch (e, st) {
561+
} catch (e, s) {
565562
// The error must have been thrown while iterating over the futures
566563
// list, or while installing a callback handler on the future.
567564
// This is a breach of the `Future` protocol, but we try to handle it
568565
// gracefully.
569566
if (remaining == 0 || eagerError) {
570-
// Throw a new Future.error.
571-
// Don't just call `_future._completeError` since that would propagate
572-
// the error too eagerly, not giving the callers time to install
573-
// error handlers.
574-
// Also, don't use `_asyncCompleteError` since that one doesn't give
575-
// zones the chance to intercept the error.
576-
return new Future.error(e, st);
567+
// Complete asynchronously to give receiver time to handle
568+
// the result.
569+
return _future.._asyncCompleteErrorObject(_interceptCaughtError(e, s));
577570
} else {
578571
// Don't allocate a list for values, thus indicating that there was an
579572
// error.
580573
// Set error to the caught exception.
581574
error = e;
582-
stackTrace = st;
575+
stackTrace = s;
583576
}
584577
}
585578
return _future;
@@ -716,9 +709,11 @@ abstract interface class Future<T> {
716709
try {
717710
result = action();
718711
} catch (error, stackTrace) {
719-
// Cannot use _completeWithErrorCallback because it completes
712+
// Cannot use `_completeWithErrorCallback` because it completes
720713
// the future synchronously.
721-
_asyncCompleteWithErrorCallback(doneSignal, error, stackTrace);
714+
doneSignal._asyncCompleteErrorObject(
715+
_interceptCaughtError(error, stackTrace),
716+
);
722717
return;
723718
}
724719
if (result is Future<bool>) {
@@ -1331,7 +1326,7 @@ abstract interface class Completer<T> {
13311326
bool get isCompleted;
13321327
}
13331328

1334-
// Helper function completing a _Future with error, but checking the zone
1329+
// Helper function completing a _Future with an error, but checking the zone
13351330
// for error replacement and missing stack trace first.
13361331
// Only used for errors that are *caught*.
13371332
// A user provided error object should use `_interceptUserError` which
@@ -1341,24 +1336,5 @@ void _completeWithErrorCallback(
13411336
Object error,
13421337
StackTrace stackTrace,
13431338
) {
1344-
var replacement = _interceptError(error, stackTrace);
1345-
if (replacement != null) {
1346-
error = replacement.error;
1347-
stackTrace = replacement.stackTrace;
1348-
}
1349-
result._completeError(error, stackTrace);
1350-
}
1351-
1352-
// Like [_completeWithErrorCallback] but completes asynchronously.
1353-
void _asyncCompleteWithErrorCallback(
1354-
_Future result,
1355-
Object error,
1356-
StackTrace stackTrace,
1357-
) {
1358-
var replacement = _interceptError(error, stackTrace);
1359-
if (replacement != null) {
1360-
error = replacement.error;
1361-
stackTrace = replacement.stackTrace;
1362-
}
1363-
result._asyncCompleteError(error, stackTrace);
1339+
result._completeErrorObject(_interceptCaughtError(error, stackTrace));
13641340
}

‎sdk/lib/async/future_impl.dart‎

Lines changed: 44 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,28 @@ AsyncError? _interceptError(Object error, StackTrace? stackTrace) {
2424
return replacement;
2525
}
2626

27+
/// As [_interceptError], but an `AsyncError` of the error if not replaced.
28+
///
29+
/// Also like [_interceptUserError], but for errors that are already
30+
/// asynchronous.
31+
AsyncError _interceptCaughtError(Object error, StackTrace? stackTrace) =>
32+
_interceptError(error, stackTrace) ?? AsyncError(error, stackTrace);
33+
2734
/// Used for user-provided error and stack trace that are to become async
2835
/// errors.
2936
///
3037
/// Allows `Zone.current.errorCallback` to intercept and modify the error,
3138
/// and sets the stack trace on the error as if it was thrown.
39+
///
40+
/// Used for errors given to async functions like [Completer.completeError]
41+
/// or [StreamController.addError].
42+
///
43+
/// For errors that are caught (and have therefore been thrown already)
44+
/// use [_interceptCaughtError], which doesn't try to set a stack trace on the
45+
/// error object.
46+
///
47+
/// Errors that are already asynchronous (coming out of streams or futures)
48+
/// should not call [Zone.errorCallback].
3249
AsyncError _interceptUserError(Object error, StackTrace? stackTrace) {
3350
var zone = Zone.current;
3451
if (!identical(zone, _rootZone)) {
@@ -64,12 +81,11 @@ abstract class _Completer<T> implements Completer<T> {
6481
@pragma("wasm:entry-point")
6582
void completeError(Object error, [StackTrace? stackTrace]) {
6683
if (!future._mayComplete) throw new StateError("Future already completed");
67-
AsyncError(:error, :stackTrace) = _interceptUserError(error, stackTrace);
68-
_completeError(error, stackTrace);
84+
_completeErrorObject(_interceptUserError(error, stackTrace));
6985
}
7086

7187
// Overridden by either a synchronous or asynchronous implementation.
72-
void _completeError(Object error, StackTrace stackTrace);
88+
void _completeErrorObject(AsyncError error);
7389

7490
// The future's _isComplete doesn't take into account pending completions.
7591
// We therefore use _mayComplete.
@@ -85,8 +101,8 @@ class _AsyncCompleter<T> extends _Completer<T> {
85101
future._asyncComplete(value == null ? value as dynamic : value);
86102
}
87103

88-
void _completeError(Object error, StackTrace stackTrace) {
89-
future._asyncCompleteError(error, stackTrace);
104+
void _completeErrorObject(AsyncError error) {
105+
future._asyncCompleteErrorObject(error);
90106
}
91107
}
92108

@@ -100,8 +116,8 @@ class _SyncCompleter<T> extends _Completer<T> {
100116
future._complete(value == null ? value as dynamic : value);
101117
}
102118

103-
void _completeError(Object error, StackTrace stackTrace) {
104-
future._completeError(error, stackTrace);
119+
void _completeErrorObject(AsyncError error) {
120+
future._completeErrorObject(error);
105121
}
106122
}
107123

@@ -351,9 +367,8 @@ class _Future<T> implements Future<T> {
351367
_setValue(value);
352368
}
353369

354-
_Future.immediateError(var error, StackTrace stackTrace)
355-
: _zone = Zone._current {
356-
_asyncCompleteError(error, stackTrace);
370+
_Future.immediateError(AsyncError error) : _zone = Zone._current {
371+
_asyncCompleteErrorObject(error);
357372
}
358373

359374
/// Creates a future that is already completed with the value.
@@ -497,10 +512,6 @@ class _Future<T> implements Future<T> {
497512
_resultOrListeners = error;
498513
}
499514

500-
void _setError(Object error, StackTrace stackTrace) {
501-
_setErrorObject(new AsyncError(error, stackTrace));
502-
}
503-
504515
/// Copy the completion result of [source] into this future.
505516
///
506517
/// Used when a chained future notices that its source is completed.
@@ -722,14 +733,18 @@ class _Future<T> implements Future<T> {
722733
_propagateToListeners(this, listeners);
723734
}
724735

725-
void _completeError(Object error, StackTrace stackTrace) {
736+
void _completeErrorObject(AsyncError error) {
726737
assert(!_isComplete);
727738

728739
_FutureListener? listeners = _removeListeners();
729-
_setError(error, stackTrace);
740+
_setErrorObject(error);
730741
_propagateToListeners(this, listeners);
731742
}
732743

744+
void _completeError(Object error, StackTrace stackTrace) {
745+
_completeErrorObject(AsyncError(error, stackTrace));
746+
}
747+
733748
// Completes future in a later microtask.
734749
void _asyncComplete(FutureOr<T> value) {
735750
assert(!_isComplete); // Allows both pending complete and incomplete.
@@ -809,11 +824,15 @@ class _Future<T> implements Future<T> {
809824
}
810825

811826
void _asyncCompleteError(Object error, StackTrace stackTrace) {
827+
_asyncCompleteErrorObject(AsyncError(error, stackTrace));
828+
}
829+
830+
void _asyncCompleteErrorObject(AsyncError error) {
812831
assert(!_isComplete);
813832

814833
_setPendingComplete();
815834
_zone.scheduleMicrotask(() {
816-
_completeError(error, stackTrace);
835+
_completeErrorObject(error);
817836
});
818837
}
819838

@@ -919,7 +938,7 @@ class _Future<T> implements Future<T> {
919938
joinedResult._completeWithResultOf(originalSource);
920939
},
921940
onError: (Object e, StackTrace s) {
922-
joinedResult._completeError(e, s);
941+
joinedResult._completeErrorObject(AsyncError(e, s));
923942
},
924943
);
925944
listenerValueOrError = joinedResult;
@@ -1020,9 +1039,11 @@ class _Future<T> implements Future<T> {
10201039
Timer timer;
10211040
if (onTimeout == null) {
10221041
timer = new Timer(timeLimit, () {
1023-
_future._completeError(
1024-
new TimeoutException("Future not completed", timeLimit),
1025-
StackTrace.current,
1042+
_future._completeErrorObject(
1043+
AsyncError(
1044+
new TimeoutException("Future not completed", timeLimit),
1045+
StackTrace.current,
1046+
),
10261047
);
10271048
});
10281049
} else {
@@ -1035,7 +1056,7 @@ class _Future<T> implements Future<T> {
10351056
try {
10361057
_future._complete(zone.run(onTimeoutHandler));
10371058
} catch (e, s) {
1038-
_future._completeError(e, s);
1059+
_future._completeErrorObject(AsyncError(e, s));
10391060
}
10401061
});
10411062
}
@@ -1049,7 +1070,7 @@ class _Future<T> implements Future<T> {
10491070
onError: (Object e, StackTrace s) {
10501071
if (timer.isActive) {
10511072
timer.cancel();
1052-
_future._completeError(e, s);
1073+
_future._completeErrorObject(AsyncError(e, s));
10531074
}
10541075
},
10551076
);

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /