Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(48)

Unified Diff: pkg/dev_compiler/tool/input_sdk/lib/async/future_impl.dart

Issue 2698353003: unfork DDC's copy of most SDK libraries (Closed)
Patch Set: revert core_patch Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: pkg/dev_compiler/tool/input_sdk/lib/async/future_impl.dart
diff --git a/pkg/dev_compiler/tool/input_sdk/lib/async/future_impl.dart b/pkg/dev_compiler/tool/input_sdk/lib/async/future_impl.dart
deleted file mode 100644
index 4e6ba423446fee6bf1eebe606b319ffbc72e26c8..0000000000000000000000000000000000000000
--- a/pkg/dev_compiler/tool/input_sdk/lib/async/future_impl.dart
+++ /dev/null
@@ -1,746 +0,0 @@
-// Copyright (c) 2012, 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.
-
-part of dart.async;
-
-/** The onValue and onError handlers return either a value or a future */
-typedef dynamic/*T|Future<T>*/ _FutureOnValue<S, T>(S value);
-/** Test used by [Future.catchError] to handle skip some errors. */
-typedef bool _FutureErrorTest(var error);
-/** Used by [WhenFuture]. */
-typedef _FutureAction();
-
-abstract class _Completer<T> implements Completer<T> {
- final _Future<T> future = new _Future<T>();
-
- void complete([value]);
-
- void completeError(Object error, [StackTrace stackTrace]) {
- error = _nonNullError(error);
- if (!future._mayComplete) throw new StateError("Future already completed");
- AsyncError replacement = Zone.current.errorCallback(error, stackTrace);
- if (replacement != null) {
- error = _nonNullError(replacement.error);
- stackTrace = replacement.stackTrace;
- }
- _completeError(error, stackTrace);
- }
-
- void _completeError(Object error, StackTrace stackTrace);
-
- // The future's _isComplete doesn't take into account pending completions.
- // We therefore use _mayComplete.
- bool get isCompleted => !future._mayComplete;
-}
-
-class _AsyncCompleter<T> extends _Completer<T> {
-
- void complete([value]) {
- if (!future._mayComplete) throw new StateError("Future already completed");
- future._asyncComplete(value);
- }
-
- void _completeError(Object error, StackTrace stackTrace) {
- future._asyncCompleteError(error, stackTrace);
- }
-}
-
-class _SyncCompleter<T> extends _Completer<T> {
- void complete([value]) {
- if (!future._mayComplete) throw new StateError("Future already completed");
- future._complete(value);
- }
-
- void _completeError(Object error, StackTrace stackTrace) {
- future._completeError(error, stackTrace);
- }
-}
-
-class _FutureListener<S, T> {
- static const int MASK_VALUE = 1;
- static const int MASK_ERROR = 2;
- static const int MASK_TEST_ERROR = 4;
- static const int MASK_WHENCOMPLETE = 8;
- static const int STATE_CHAIN = 0;
- static const int STATE_THEN = MASK_VALUE;
- // TODO(johnmccutchan): Remove the hard coded value. See #26030.
- static const int STATE_THEN_ONERROR = 3; // MASK_VALUE | MASK_ERROR.
- static const int STATE_CATCHERROR = MASK_ERROR;
- // TODO(johnmccutchan): Remove the hard coded value. See #26030.
- static const int STATE_CATCHERROR_TEST = 6; // MASK_ERROR | MASK_TEST_ERROR.
- static const int STATE_WHENCOMPLETE = MASK_WHENCOMPLETE;
- // Listeners on the same future are linked through this link.
- _FutureListener _nextListener = null;
- // The future to complete when this listener is activated.
- final _Future<T> result;
- // Which fields means what.
- final int state;
- // Used for then/whenDone callback and error test
- final Function callback;
- // Used for error callbacks.
- final Function errorCallback;
-
- _FutureListener.then(this.result,
- _FutureOnValue<S, T> onValue, Function errorCallback)
- : callback = onValue,
- errorCallback = errorCallback,
- state = (errorCallback == null) ? STATE_THEN : STATE_THEN_ONERROR;
-
- _FutureListener.catchError(this.result,
- this.errorCallback, _FutureErrorTest test)
- : callback = test,
- state = (test == null) ? STATE_CATCHERROR : STATE_CATCHERROR_TEST;
-
- _FutureListener.whenComplete(this.result, _FutureAction onComplete)
- : callback = onComplete,
- errorCallback = null,
- state = STATE_WHENCOMPLETE;
-
- Zone get _zone => result._zone;
-
- bool get handlesValue => (state & MASK_VALUE != 0);
- bool get handlesError => (state & MASK_ERROR != 0);
- bool get hasErrorTest => (state == STATE_CATCHERROR_TEST);
- bool get handlesComplete => (state == STATE_WHENCOMPLETE);
-
-
- _FutureOnValue<S, T> get _onValue {
- assert(handlesValue);
- return callback as Object /*=_FutureOnValue<S, T>*/;
- }
- Function get _onError => errorCallback;
- _FutureErrorTest get _errorTest {
- assert(hasErrorTest);
- return callback as Object /*=_FutureErrorTest*/;
- }
- _FutureAction get _whenCompleteAction {
- assert(handlesComplete);
- return callback as Object /*=_FutureAction*/;
- }
-
- /// Whether this listener has an error callback.
- ///
- /// This function must only be called if the listener [handlesError].
- bool get hasErrorCallback {
- assert(handlesError);
- return _onError != null;
- }
-
- dynamic/*T|Future<T>*/ handleValue(S sourceResult) {
- return _zone.runUnary<dynamic/*T|Future<T>*/, S>(
- _onValue, sourceResult);
- }
-
- bool matchesErrorTest(AsyncError asyncError) {
- if (!hasErrorTest) return true;
- _FutureErrorTest test = _errorTest;
- return _zone.runUnary<bool, dynamic>(_errorTest, asyncError.error);
- }
-
- dynamic/*T|Future<T>*/ handleError(AsyncError asyncError) {
- assert(handlesError && hasErrorCallback);
- if (errorCallback is ZoneBinaryCallback) {
- var typedErrorCallback = errorCallback as Object
- /*=ZoneBinaryCallback<Object/*T|Future<T>*/, Object, StackTrace>*/;
- return _zone.runBinary(typedErrorCallback,
- asyncError.error,
- asyncError.stackTrace);
- } else {
- return _zone.runUnary<dynamic/*T|Future<T>*/, dynamic>(
- errorCallback, asyncError.error);
- }
- }
-
- dynamic handleWhenComplete() {
- assert(!handlesError);
- return _zone.run(_whenCompleteAction);
- }
-}
-
-class _Future<T> implements Future<T> {
- /// Initial state, waiting for a result. In this state, the
- /// [resultOrListeners] field holds a single-linked list of
- /// [_FutureListener] listeners.
- static const int _INCOMPLETE = 0;
- /// Pending completion. Set when completed using [_asyncComplete] or
- /// [_asyncCompleteError]. It is an error to try to complete it again.
- /// [resultOrListeners] holds listeners.
- static const int _PENDING_COMPLETE = 1;
- /// The future has been chained to another future. The result of that
- /// other future becomes the result of this future as well.
- /// [resultOrListeners] contains the source future.
- static const int _CHAINED = 2;
- /// The future has been completed with a value result.
- static const int _VALUE = 4;
- /// The future has been completed with an error result.
- static const int _ERROR = 8;
-
- /** Whether the future is complete, and as what. */
- int _state = _INCOMPLETE;
-
- /**
- * Zone that the future was completed from.
- * This is the zone that an error result belongs to.
- *
- * Until the future is completed, the field may hold the zone that
- * listener callbacks used to create this future should be run in.
- */
- final Zone _zone = Zone.current;
-
- /**
- * Either the result, a list of listeners or another future.
- *
- * The result of the future is either a value or an error.
- * A result is only stored when the future has completed.
- *
- * The listeners is an internally linked list of [_FutureListener]s.
- * Listeners are only remembered while the future is not yet complete,
- * and it is not chained to another future.
- *
- * The future is another future that his future is chained to. This future
- * is waiting for the other future to complete, and when it does, this future
- * will complete with the same result.
- * All listeners are forwarded to the other future.
- */
- var _resultOrListeners;
-
- // This constructor is used by async/await.
- _Future();
-
- /// Valid types for value: `T` or `Future<T>`.
- _Future.immediate(value) {
- _asyncComplete(value);
- }
-
- _Future.immediateError(var error, [StackTrace stackTrace]) {
- _asyncCompleteError(error, stackTrace);
- }
-
- bool get _mayComplete => _state == _INCOMPLETE;
- bool get _isPendingComplete => _state == _PENDING_COMPLETE;
- bool get _mayAddListener => _state <= _PENDING_COMPLETE;
- bool get _isChained => _state == _CHAINED;
- bool get _isComplete => _state >= _VALUE;
- bool get _hasError => _state == _ERROR;
-
- void _setChained(_Future source) {
- assert(_mayAddListener);
- _state = _CHAINED;
- _resultOrListeners = source;
- }
-
- Future<E> then<E>(
- FutureOr<E> f(T value), { Function onError }) {
- Zone currentZone = Zone.current;
- ZoneUnaryCallback registered;
- if (!identical(currentZone, _ROOT_ZONE)) {
- f = currentZone.registerUnaryCallback<FutureOr<E>, T>(f);
- if (onError != null) {
- onError = _registerErrorHandler<T>(onError, currentZone);
- }
- }
- return _thenNoZoneRegistration<E>(f, onError);
- }
-
- // This method is used by async/await.
- Future<E> _thenNoZoneRegistration<E>(f(T value), Function onError) {
- _Future<E> result = new _Future<E>();
- _addListener(new _FutureListener<T, E>.then(result, f, onError));
- return result;
- }
-
- Future<T> catchError(Function onError, { bool test(error) }) {
- _Future<T> result = new _Future<T>();
- if (!identical(result._zone, _ROOT_ZONE)) {
- onError = _registerErrorHandler<T>(onError, result._zone);
- if (test != null) test = result._zone.registerUnaryCallback(test);
- }
- _addListener(new _FutureListener<T, T>.catchError(
- result, onError, test));
- return result;
- }
-
- Future<T> whenComplete(action()) {
- _Future<T> result = new _Future<T>();
- if (!identical(result._zone, _ROOT_ZONE)) {
- action = result._zone.registerCallback<dynamic>(action);
- }
- _addListener(new _FutureListener<T, T>.whenComplete(result, action));
- return result;
- }
-
- Stream<T> asStream() => new Stream<T>.fromFuture(this);
-
- void _setPendingComplete() {
- assert(_mayComplete);
- _state = _PENDING_COMPLETE;
- }
-
- void _clearPendingComplete() {
- assert(_isPendingComplete);
- _state = _INCOMPLETE;
- }
-
- AsyncError get _error {
- assert(_hasError);
- return _resultOrListeners;
- }
-
- _Future get _chainSource {
- assert(_isChained);
- return _resultOrListeners;
- }
-
- // This method is used by async/await.
- void _setValue(T value) {
- assert(!_isComplete); // But may have a completion pending.
- _state = _VALUE;
- _resultOrListeners = value;
- }
-
- void _setErrorObject(AsyncError error) {
- assert(!_isComplete); // But may have a completion pending.
- _state = _ERROR;
- _resultOrListeners = error;
- }
-
- void _setError(Object error, StackTrace stackTrace) {
- _setErrorObject(new AsyncError(error, stackTrace));
- }
-
- /// Copy the completion result of [source] into this future.
- ///
- /// Used when a chained future notices that its source is completed.
- void _cloneResult(_Future source) {
- assert(!_isComplete);
- assert(source._isComplete);
- _state = source._state;
- _resultOrListeners = source._resultOrListeners;
- }
-
- void _addListener(_FutureListener listener) {
- assert(listener._nextListener == null);
- if (_mayAddListener) {
- listener._nextListener = _resultOrListeners;
- _resultOrListeners = listener;
- } else {
- if (_isChained) {
- // Delegate listeners to chained source future.
- // If the source is complete, instead copy its values and
- // drop the chaining.
- _Future source = _chainSource;
- if (!source._isComplete) {
- source._addListener(listener);
- return;
- }
- _cloneResult(source);
- }
- assert(_isComplete);
- // Handle late listeners asynchronously.
- _zone.scheduleMicrotask(() {
- _propagateToListeners(this, listener);
- });
- }
- }
-
- void _prependListeners(_FutureListener listeners) {
- if (listeners == null) return;
- if (_mayAddListener) {
- _FutureListener existingListeners = _resultOrListeners;
- _resultOrListeners = listeners;
- if (existingListeners != null) {
- _FutureListener cursor = listeners;
- while (cursor._nextListener != null) {
- cursor = cursor._nextListener;
- }
- cursor._nextListener = existingListeners;
- }
- } else {
- if (_isChained) {
- // Delegate listeners to chained source future.
- // If the source is complete, instead copy its values and
- // drop the chaining.
- _Future source = _chainSource;
- if (!source._isComplete) {
- source._prependListeners(listeners);
- return;
- }
- _cloneResult(source);
- }
- assert(_isComplete);
- listeners = _reverseListeners(listeners);
- _zone.scheduleMicrotask(() {
- _propagateToListeners(this, listeners);
- });
- }
- }
-
- _FutureListener _removeListeners() {
- // Reverse listeners before returning them, so the resulting list is in
- // subscription order.
- assert(!_isComplete);
- _FutureListener current = _resultOrListeners;
- _resultOrListeners = null;
- return _reverseListeners(current);
- }
-
- _FutureListener _reverseListeners(_FutureListener listeners) {
- _FutureListener prev = null;
- _FutureListener current = listeners;
- while (current != null) {
- _FutureListener next = current._nextListener;
- current._nextListener = prev;
- prev = current;
- current = next;
- }
- return prev;
- }
-
- // Take the value (when completed) of source and complete target with that
- // value (or error). This function could chain all Futures, but is slower
- // for _Future than _chainCoreFuture, so you must use _chainCoreFuture
- // in that case.
- static void _chainForeignFuture(Future source, _Future target) {
- assert(!target._isComplete);
- assert(source is! _Future);
-
- // Mark the target as chained (and as such half-completed).
- target._setPendingComplete();
- try {
- source.then((value) {
- assert(target._isPendingComplete);
- // The "value" may be another future if the foreign future
- // implementation is mis-behaving,
- // so use _complete instead of _completeWithValue.
- target._clearPendingComplete(); // Clear this first, it's set again.
- target._complete(value);
- },
- // TODO(floitsch): eventually we would like to make this non-optional
- // and dependent on the listeners of the target future. If none of
- // the target future's listeners want to have the stack trace we don't
- // need a trace.
- onError: (error, [stackTrace]) {
- assert(target._isPendingComplete);
- target._completeError(error, stackTrace);
- });
- } catch (e, s) {
- // This only happens if the `then` call threw synchronously when given
- // valid arguments.
- // That requires a non-conforming implementation of the Future interface,
- // which should, hopefully, never happen.
- scheduleMicrotask(() {
- target._completeError(e, s);
- });
- }
- }
-
- // Take the value (when completed) of source and complete target with that
- // value (or error). This function expects that source is a _Future.
- static void _chainCoreFuture(_Future source, _Future target) {
- assert(target._mayAddListener); // Not completed, not already chained.
- while (source._isChained) {
- source = source._chainSource;
- }
- if (source._isComplete) {
- _FutureListener listeners = target._removeListeners();
- target._cloneResult(source);
- _propagateToListeners(target, listeners);
- } else {
- _FutureListener listeners = target._resultOrListeners;
- target._setChained(source);
- source._prependListeners(listeners);
- }
- }
-
- void _complete(value) {
- assert(!_isComplete);
- if (value is Future) {
- if (value is _Future) {
- _chainCoreFuture(value, this);
- } else {
- _chainForeignFuture(value, this);
- }
- } else {
- _FutureListener listeners = _removeListeners();
- _setValue(value as Object /*=T*/);
- _propagateToListeners(this, listeners);
- }
- }
-
- void _completeWithValue(T value) {
- assert(!_isComplete);
- assert(value is! Future);
-
- _FutureListener listeners = _removeListeners();
- _setValue(value);
- _propagateToListeners(this, listeners);
- }
-
- void _completeError(error, [StackTrace stackTrace]) {
- assert(!_isComplete);
-
- _FutureListener listeners = _removeListeners();
- _setError(error, stackTrace);
- _propagateToListeners(this, listeners);
- }
-
- void _asyncComplete(value) {
- assert(!_isComplete);
- // Two corner cases if the value is a future:
- // 1. the future is already completed and an error.
- // 2. the future is not yet completed but might become an error.
- // The first case means that we must not immediately complete the Future,
- // as our code would immediately start propagating the error without
- // giving the time to install error-handlers.
- // However the second case requires us to deal with the value immediately.
- // Otherwise the value could complete with an error and report an
- // unhandled error, even though we know we are already going to listen to
- // it.
-
- if (value is Future) {
- // Assign to typed variables so we get earlier checks in checked mode.
- Future<T> typedFuture = value as Object /*=Future<T>*/;
- if (typedFuture is _Future) {
- _Future<T> coreFuture = typedFuture;
- if (coreFuture._hasError) {
- // Case 1 from above. Delay completion to enable the user to register
- // callbacks.
- _setPendingComplete();
- _zone.scheduleMicrotask(() {
- _chainCoreFuture(coreFuture, this);
- });
- } else {
- _chainCoreFuture(coreFuture, this);
- }
- } else {
- // Case 2 from above. Chain the future immediately.
- // Note that we are still completing asynchronously (through
- // _chainForeignFuture).
- _chainForeignFuture(typedFuture, this);
- }
- return;
- }
- T typedValue = value as Object /*=T*/;
-
- _setPendingComplete();
- _zone.scheduleMicrotask(() {
- _completeWithValue(typedValue);
- });
- }
-
- void _asyncCompleteError(error, StackTrace stackTrace) {
- assert(!_isComplete);
-
- _setPendingComplete();
- _zone.scheduleMicrotask(() {
- _completeError(error, stackTrace);
- });
- }
-
- /**
- * Propagates the value/error of [source] to its [listeners], executing the
- * listeners' callbacks.
- */
- static void _propagateToListeners(_Future source, _FutureListener listeners) {
- while (true) {
- assert(source._isComplete);
- bool hasError = source._hasError;
- if (listeners == null) {
- if (hasError) {
- AsyncError asyncError = source._error;
- source._zone.handleUncaughtError(
- asyncError.error, asyncError.stackTrace);
- }
- return;
- }
- // Usually futures only have one listener. If they have several, we
- // call handle them separately in recursive calls, continuing
- // here only when there is only one listener left.
- while (listeners._nextListener != null) {
- _FutureListener listener = listeners;
- listeners = listener._nextListener;
- listener._nextListener = null;
- _propagateToListeners(source, listener);
- }
- _FutureListener listener = listeners;
- final sourceResult = source._resultOrListeners;
- // Do the actual propagation.
- // Set initial state of listenerHasError and listenerValueOrError. These
- // variables are updated with the outcome of potential callbacks.
- // Non-error results, including futures, are stored in
- // listenerValueOrError and listenerHasError is set to false. Errors
- // are stored in listenerValueOrError as an [AsyncError] and
- // listenerHasError is set to true.
- bool listenerHasError = hasError;
- var listenerValueOrError = sourceResult;
-
- // Only if we either have an error or callbacks, go into this, somewhat
- // expensive, branch. Here we'll enter/leave the zone. Many futures
- // don't have callbacks, so this is a significant optimization.
- if (hasError || listener.handlesValue || listener.handlesComplete) {
- Zone zone = listener._zone;
- if (hasError && !source._zone.inSameErrorZone(zone)) {
- // Don't cross zone boundaries with errors.
- AsyncError asyncError = source._error;
- source._zone.handleUncaughtError(
- asyncError.error, asyncError.stackTrace);
- return;
- }
-
- Zone oldZone;
- if (!identical(Zone.current, zone)) {
- // Change zone if it's not current.
- oldZone = Zone._enter(zone);
- }
-
- // These callbacks are abstracted to isolate the try/catch blocks
- // from the rest of the code to work around a V8 glass jaw.
- void handleWhenCompleteCallback() {
- // The whenComplete-handler is not combined with normal value/error
- // handling. This means at most one handleX method is called per
- // listener.
- assert(!listener.handlesValue);
- assert(!listener.handlesError);
- var completeResult;
- try {
- completeResult = listener.handleWhenComplete();
- } catch (e, s) {
- if (hasError && identical(source._error.error, e)) {
- listenerValueOrError = source._error;
- } else {
- listenerValueOrError = new AsyncError(e, s);
- }
- listenerHasError = true;
- return;
- }
- if (completeResult is Future) {
- if (completeResult is _Future && completeResult._isComplete) {
- if (completeResult._hasError) {
- listenerValueOrError = completeResult._error;
- listenerHasError = true;
- }
- // Otherwise use the existing result of source.
- return;
- }
- // We have to wait for the completeResult future to complete
- // before knowing if it's an error or we should use the result
- // of source.
- var originalSource = source;
- listenerValueOrError = completeResult.then((_) => originalSource);
- listenerHasError = false;
- }
- }
-
- void handleValueCallback() {
- try {
- listenerValueOrError = listener.handleValue(sourceResult);
- } catch (e, s) {
- listenerValueOrError = new AsyncError(e, s);
- listenerHasError = true;
- }
- }
-
- void handleError() {
- try {
- AsyncError asyncError = source._error;
- if (listener.matchesErrorTest(asyncError) &&
- listener.hasErrorCallback) {
- listenerValueOrError = listener.handleError(asyncError);
- listenerHasError = false;
- }
- } catch (e, s) {
- if (identical(source._error.error, e)) {
- listenerValueOrError = source._error;
- } else {
- listenerValueOrError = new AsyncError(e, s);
- }
- listenerHasError = true;
- }
- }
-
-
- if (listener.handlesComplete) {
- handleWhenCompleteCallback();
- } else if (!hasError) {
- if (listener.handlesValue) {
- handleValueCallback();
- }
- } else {
- if (listener.handlesError) {
- handleError();
- }
- }
-
- // If we changed zone, oldZone will not be null.
- if (oldZone != null) Zone._leave(oldZone);
-
- // If the listener's value is a future we need to chain it. Note that
- // this can only happen if there is a callback.
- if (listenerValueOrError is Future) {
- Future chainSource = listenerValueOrError;
- // Shortcut if the chain-source is already completed. Just continue
- // the loop.
- _Future result = listener.result;
- if (chainSource is _Future) {
- if (chainSource._isComplete) {
- listeners = result._removeListeners();
- result._cloneResult(chainSource);
- source = chainSource;
- continue;
- } else {
- _chainCoreFuture(chainSource, result);
- }
- } else {
- _chainForeignFuture(chainSource, result);
- }
- return;
- }
- }
- _Future result = listener.result;
- listeners = result._removeListeners();
- if (!listenerHasError) {
- result._setValue(listenerValueOrError);
- } else {
- AsyncError asyncError = listenerValueOrError;
- result._setErrorObject(asyncError);
- }
- // Prepare for next round.
- source = result;
- }
- }
-
- Future<T> timeout(Duration timeLimit, {onTimeout()}) {
- if (_isComplete) return new _Future.immediate(this);
- _Future<T> result = new _Future<T>();
- Timer timer;
- if (onTimeout == null) {
- timer = new Timer(timeLimit, () {
- result._completeError(new TimeoutException("Future not completed",
- timeLimit));
- });
- } else {
- Zone zone = Zone.current;
- onTimeout = zone.registerCallback(onTimeout);
- timer = new Timer(timeLimit, () {
- try {
- result._complete(zone.run(onTimeout));
- } catch (e, s) {
- result._completeError(e, s);
- }
- });
- }
- this.then((T v) {
- if (timer.isActive) {
- timer.cancel();
- result._completeWithValue(v);
- }
- }, onError: (e, s) {
- if (timer.isActive) {
- timer.cancel();
- result._completeError(e, s);
- }
- });
- return result;
- }
-}

Powered by Google App Engine
This is Rietveld 408576698