Add missing null-tests to async error functions.
Also treat null errors comming out of Zone.errorCallback as NullThrownError. This should prevent, as was always the intention, any async error from having a null value. This is important for async/await syntax, where the distinction between sync and async errors is removed. (For Dart 2.0, we could just make null throwable). R=sgjesse@google.com Review URL: https://codereview.chromium.org//598993002 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@40673 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
@@ -238,10 +238,11 @@ abstract class _BroadcastStreamController<T>
|
||||
}
|
||||
|
||||
void addError(Object error, [StackTrace stackTrace]) {
|
||||
error = _nonNullError(error);
|
||||
if (!_mayAddEvent) throw _addEventError();
|
||||
AsyncError replacement = Zone.current.errorCallback(error, stackTrace);
|
||||
if (replacement != null) {
|
||||
error = replacement.error;
|
||||
error = _nonNullError(replacement.error);
|
||||
stackTrace = replacement.stackTrace;
|
||||
}
|
||||
_sendError(error, stackTrace);
|
||||
|
||||
@@ -187,13 +187,16 @@ abstract class Future<T> {
|
||||
/**
|
||||
* A future that completes with an error in the next event-loop iteration.
|
||||
*
|
||||
* Use [Completer] to create a Future and complete it later.
|
||||
* If [error] is `null`, it is replaced by a [NullThrownError].
|
||||
*
|
||||
* Use [Completer] to create a future and complete it later.
|
||||
*/
|
||||
factory Future.error(Object error, [StackTrace stackTrace]) {
|
||||
error = _nonNullError(error);
|
||||
if (!identical(Zone.current, _ROOT_ZONE)) {
|
||||
AsyncError replacement = Zone.current.errorCallback(error, stackTrace);
|
||||
if (replacement != null) {
|
||||
error = replacement.error;
|
||||
error = _nonNullError(replacement.error);
|
||||
stackTrace = replacement.stackTrace;
|
||||
}
|
||||
}
|
||||
@@ -663,10 +666,13 @@ abstract class Completer<T> {
|
||||
// for error replacement first.
|
||||
void _completeWithErrorCallback(_Future result, error, stackTrace) {
|
||||
AsyncError replacement = Zone.current.errorCallback(error, stackTrace);
|
||||
if (replacement == null) {
|
||||
result._completeError(error, stackTrace);
|
||||
} else {
|
||||
result._completeError(replacement.error, replacement.stackTrace);
|
||||
if (replacement != null) {
|
||||
error = _nonNullError(replacement.error);
|
||||
stackTrace = replacement.stackTrace;
|
||||
}
|
||||
result._completeError(error, stackTrace);
|
||||
}
|
||||
|
||||
/** Helper function that converts `null` to a [NullThrownError]. */
|
||||
Object _nonNullError(Object error) =>
|
||||
(error != null) ? error : new NullThrownError();
|
||||
|
||||
@@ -17,11 +17,11 @@ abstract class _Completer<T> implements Completer<T> {
|
||||
void complete([value]);
|
||||
|
||||
void completeError(Object error, [StackTrace stackTrace]) {
|
||||
if (error == null) throw new ArgumentError("Error must not be null");
|
||||
error = _nonNullError(error);
|
||||
if (!future._mayComplete) throw new StateError("Future already completed");
|
||||
AsyncError replacement = Zone.current.errorCallback(error, stackTrace);
|
||||
if (replacement != null) {
|
||||
error = replacement.error;
|
||||
error = _nonNullError(replacement.error);
|
||||
stackTrace = replacement.stackTrace;
|
||||
}
|
||||
_completeError(error, stackTrace);
|
||||
@@ -47,7 +47,6 @@ class _AsyncCompleter<T> extends _Completer<T> {
|
||||
}
|
||||
|
||||
class _SyncCompleter<T> extends _Completer<T> {
|
||||
|
||||
void complete([value]) {
|
||||
if (!future._mayComplete) throw new StateError("Future already completed");
|
||||
future._complete(value);
|
||||
|
||||
@@ -1382,7 +1382,7 @@ abstract class EventSink<T> implements Sink<T> {
|
||||
void add(T event);
|
||||
/** Send an async error to a stream. */
|
||||
void addError(errorEvent, [StackTrace stackTrace]);
|
||||
/** Send a done event to a stream.*/
|
||||
/** Send a done event to a stream. */
|
||||
void close();
|
||||
}
|
||||
|
||||
|
||||
@@ -168,6 +168,8 @@ abstract class StreamController<T> implements StreamSink<T> {
|
||||
/**
|
||||
* Send or enqueue an error event.
|
||||
*
|
||||
* If [error] is `null`, it is replaced by a [NullThrownError].
|
||||
*
|
||||
* Also allows an objection stack trace object, on top of what [EventSink]
|
||||
* allows.
|
||||
*/
|
||||
@@ -414,10 +416,11 @@ abstract class _StreamController<T> implements StreamController<T>,
|
||||
* Send or enqueue an error event.
|
||||
*/
|
||||
void addError(Object error, [StackTrace stackTrace]) {
|
||||
error = _nonNullError(error);
|
||||
if (!_mayAddEvent) throw _badEventState();
|
||||
AsyncError replacement = Zone.current.errorCallback(error, stackTrace);
|
||||
if (replacement != null) {
|
||||
error = replacement.error;
|
||||
error = _nonNullError(replacement.error);
|
||||
stackTrace = replacement.stackTrace;
|
||||
}
|
||||
_addError(error, stackTrace);
|
||||
|
||||
@@ -15,7 +15,9 @@ _runUserCode(userCode(),
|
||||
if (replacement == null) {
|
||||
onError(e, s);
|
||||
} else {
|
||||
onError(replacement.error, replacement.stackTrace);
|
||||
var error = _nonNullError(replacement.error);
|
||||
var stackTrace = replacement.stackTrace;
|
||||
onError(error, stackTrace);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -39,7 +41,7 @@ void _cancelAndErrorWithReplacement(StreamSubscription subscription,
|
||||
error, StackTrace stackTrace) {
|
||||
AsyncError replacement = Zone.current.errorCallback(error, stackTrace);
|
||||
if (replacement != null) {
|
||||
error = replacement.error;
|
||||
error = _nonNullError(replacement.error);
|
||||
stackTrace = replacement.stackTrace;
|
||||
}
|
||||
_cancelAndError(subscription, future, error, stackTrace);
|
||||
@@ -187,11 +189,11 @@ typedef bool _Predicate<T>(T value);
|
||||
|
||||
void _addErrorWithReplacement(_EventSink sink, error, stackTrace) {
|
||||
AsyncError replacement = Zone.current.errorCallback(error, stackTrace);
|
||||
if (replacement == null) {
|
||||
sink._addError(error, stackTrace);
|
||||
} else {
|
||||
sink._addError(replacement.error, replacement.stackTrace);
|
||||
if (replacement != null) {
|
||||
error = _nonNullError(replacement.error);
|
||||
stackTrace = replacement.stackTrace;
|
||||
}
|
||||
sink._addError(error, stackTrace);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -36,12 +36,13 @@ typedef Zone ForkHandler(Zone self, ZoneDelegate parent, Zone zone,
|
||||
ZoneSpecification specification,
|
||||
Map zoneValues);
|
||||
|
||||
/// Pair of error and stack trace. Returned by [Zone.errorCallback].
|
||||
/** Pair of error and stack trace. Returned by [Zone.errorCallback]. */
|
||||
class AsyncError implements Error {
|
||||
final error;
|
||||
final StackTrace stackTrace;
|
||||
|
||||
AsyncError(this.error, this.stackTrace);
|
||||
|
||||
String toString() => error.toString();
|
||||
}
|
||||
|
||||
@@ -254,10 +255,10 @@ abstract class Zone {
|
||||
// Private constructor so that it is not possible instantiate a Zone class.
|
||||
Zone._();
|
||||
|
||||
/// The root zone that is implicitly created.
|
||||
/** The root zone that is implicitly created. */
|
||||
static const Zone ROOT = _ROOT_ZONE;
|
||||
|
||||
/// The currently running zone.
|
||||
/** The currently running zone. */
|
||||
static Zone _current = _ROOT_ZONE;
|
||||
|
||||
static Zone get current => _current;
|
||||
|
||||
@@ -17,7 +17,7 @@ LibTest/isolate/IsolateStream/contains_A02_t01: Fail # co19 issue 668
|
||||
LibTest/typed_data/ByteData/buffer_A01_t01: Fail # co19 r736 bug - sent comment.
|
||||
|
||||
# TODO(terry) re-enable the below CSS tests when Chrome 38 and (Dartium 38) are ready issue 21075
|
||||
LayoutTests/fast/css/getComputedStyle/computed-style-font_t01: Skip
|
||||
LayoutTests/fast/css/getComputedStyle/computed-style-font_t01: Skip
|
||||
LayoutTests/fast/css/font-shorthand-from-longhands_t01: Skip
|
||||
|
||||
Language/07_Classes/6_Constructors/1_Generative_Constructors_A01_t06: Fail, Pass, OK # co19 issue 695
|
||||
@@ -29,6 +29,8 @@ WebPlatformTest/shadow-dom/elements-and-dom-objects/shadowroot-object/shadowroot
|
||||
[ $compiler != dartanalyzer && $compiler != dart2analyzer ]
|
||||
# Tests that fail on every runtime, but not on the analyzer.
|
||||
|
||||
LibTest/async/Future/Future.error_A01_t01: RuntimeError # co19 issue 712
|
||||
LibTest/async/Completer/completeError_A02_t01: RuntimeError # co19 issue 712
|
||||
LibTest/isolate/ReceivePort/asBroadcastStream_A02_t01: Fail # co19 issue 687
|
||||
LibTest/async/Stream/asBroadcastStream_A02_t01: Fail # co19 issue 687
|
||||
|
||||
|
||||
@@ -677,8 +677,13 @@ void testCompleteErrorWithCustomFuture() {
|
||||
}
|
||||
|
||||
void testCompleteErrorWithNull() {
|
||||
asyncStart();
|
||||
final completer = new Completer<int>();
|
||||
Expect.throws(() => completer.completeError(null));
|
||||
completer.future.catchError((e) {
|
||||
Expect.isTrue(e is NullThrownError);
|
||||
asyncEnd();
|
||||
});
|
||||
completer.completeError(null);
|
||||
}
|
||||
|
||||
void testChainedFutureValue() {
|
||||
|
||||
@@ -380,7 +380,7 @@ testRethrow() {
|
||||
Stream s = streamErrorTransform(c.stream, (e) { throw error; });
|
||||
s.listen((_) { Expect.fail("unexpected value"); }, onError: expectAsync(
|
||||
(e) { Expect.identical(error, e); }));
|
||||
c.addError(null);
|
||||
c.addError("SOME ERROR");
|
||||
c.close();
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user