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

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

Issue 2647833002: fix #28008, fix #28009 implement FutureOr<T> (Closed)
Patch Set: Merge remote-tracking branch 'origin/master' into 28008_futureort Created 3 years, 11 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
« no previous file with comments | « pkg/dev_compiler/test/codegen_test.dart ('k') | pkg/dev_compiler/tool/input_sdk/lib/async/future_impl.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/dev_compiler/tool/input_sdk/lib/async/future.dart
diff --git a/pkg/dev_compiler/tool/input_sdk/lib/async/future.dart b/pkg/dev_compiler/tool/input_sdk/lib/async/future.dart
index 815f526558764d8b6ab574cdbb53bf525388fac8..49b2460524c27e21f121043531bb7e773e399dfd 100644
--- a/pkg/dev_compiler/tool/input_sdk/lib/async/future.dart
+++ b/pkg/dev_compiler/tool/input_sdk/lib/async/future.dart
@@ -4,6 +4,46 @@
part of dart.async;
+/// A type representing values that are either `Future<T>` or `T`.
+///
+/// This class declaration is a public stand-in for an internal
+/// future-or-value generic type. References to this class are resolved to the
+/// internal type.
+///
+/// It is a compile-time error for any class to extend, mix in or implement
+/// `FutureOr`.
+///
+/// Note: the `FutureOr<T>` type is interpreted as `dynamic` in non strong-mode.
+///
+/// # Examples
+/// ``` dart
+/// // The `Future<T>.then` function takes a callback [f] that returns either
+/// // an `S` or a `Future<S>`.
+/// Future<S> then<S>(FutureOr<S> f(T x), ...);
+///
+/// // `Completer<T>.complete` takes either a `T` or `Future<T>`.
+/// void complete(FutureOr<T> value);
+/// ```
+///
+/// # Advanced
+/// The `FutureOr<int>` type is actually the "type union" of the types `int` and
+/// `Future<int>`. This type union is defined in such a way that
+/// `FutureOr<Object>` is both a super- and sub-type of `Object` (sub-type
+/// because `Object` is one of the types of the union, super-type because
+/// `Object` is a super-type of both of the types of the union). Together it
+/// means that `FutureOr<Object>` is equivalent to `Object`.
+///
+/// As a corollary, `FutureOr<Object>` is equivalent to
+/// `FutureOr<FutureOr<Object>>`, `FutureOr<Future<Object>> is equivalent to
+/// `Future<Object>`.
+abstract class FutureOr<T> {
+ // Private constructor, so that it is not subclassable, mixable, or
+ // instantiable.
+ FutureOr._() {
+ throw new UnsupportedError("FutureOr can't be instantiated");
+ }
+}
+
/**
* An object representing a delayed computation.
*
@@ -225,7 +265,7 @@ abstract class Future<T> {
_Future<T> result = new _Future<T>();
new Timer(duration, () {
try {
- result._complete(computation == null ? null : computation());
+ result._complete(computation?.call());
} catch (e, s) {
_completeWithErrorCallback(result, e, s);
}
@@ -254,11 +294,11 @@ abstract class Future<T> {
* The call to `cleanUp` should not throw. If it does, the error will be an
* uncaught asynchronous error.
*/
- static Future<List/*<T>*/> wait/*<T>*/(Iterable<Future/*<T>*/> futures,
+ static Future<List<T>> wait<T>(Iterable<Future<T>> futures,
{bool eagerError: false,
- void cleanUp(/*=T*/ successValue)}) {
- final _Future<List/*<T>*/> result = new _Future<List/*<T>*/>();
- List/*<T>*/ values; // Collects the values. Set to null on error.
+ void cleanUp(T successValue)}) {
+ final _Future<List<T>> result = new _Future<List<T>>();
+ List<T> values; // Collects the values. Set to null on error.
int remaining = 0; // How many futures are we waiting for.
var error; // The first error from a future.
StackTrace stackTrace; // The stackTrace that came with the error.
@@ -287,32 +327,56 @@ abstract class Future<T> {
}
}
- // As each future completes, put its value into the corresponding
- // position in the list of values.
- for (Future future in futures) {
- int pos = remaining++;
- future.then((Object/*=T*/ value) {
- remaining--;
- if (values != null) {
- values[pos] = value;
- if (remaining == 0) {
- result._completeWithValue(values);
- }
- } else {
- if (cleanUp != null && value != null) {
- // Ensure errors from cleanUp are uncaught.
- new Future.sync(() { cleanUp(value); });
- }
- if (remaining == 0 && !eagerError) {
- result._completeError(error, stackTrace);
+ try {
+ // As each future completes, put its value into the corresponding
+ // position in the list of values.
+ for (Future future in futures) {
+ int pos = remaining;
+ future.then((T value) {
+ remaining--;
+ if (values != null) {
+ values[pos] = value;
+ if (remaining == 0) {
+ result._completeWithValue(values);
+ }
+ } else {
+ if (cleanUp != null && value != null) {
+ // Ensure errors from cleanUp are uncaught.
+ new Future.sync(() { cleanUp(value); });
+ }
+ if (remaining == 0 && !eagerError) {
+ result._completeError(error, stackTrace);
+ }
}
- }
- }, onError: handleError);
- }
- if (remaining == 0) {
- return new Future.value(const []);
+ }, onError: handleError);
+ // Increment the 'remaining' after the call to 'then'.
+ // If that call throws, we don't expect any future callback from
+ // the future, and we also don't increment remaining.
+ remaining++;
+ }
+ if (remaining == 0) {
+ return new Future.value(const []);
+ }
+ values = new List<T>(remaining);
+ } catch (e, st) {
+ // The error must have been thrown while iterating over the futures
+ // list, or while installing a callback handler on the future.
+ if (remaining == 0 || eagerError) {
+ // Throw a new Future.error.
+ // Don't just call `result._completeError` since that would propagate
+ // the error too eagerly, not giving the callers time to install
+ // error handlers.
+ // Also, don't use `_asyncCompleteError` since that one doesn't give
+ // zones the chance to intercept the error.
+ return new Future.error(e, st);
+ } else {
+ // Don't allocate a list for values, thus indicating that there was an
+ // error.
+ // Set error to the caught exception.
+ error = e;
+ stackTrace = st;
+ }
}
- values = new List/*<T>*/(remaining);
return result;
}
@@ -326,9 +390,9 @@ abstract class Future<T> {
* If [futures] is empty, or if none of its futures complete,
* the returned future never completes.
*/
- static Future/*<T>*/ any/*<T>*/(Iterable<Future/*<T>*/> futures) {
- var completer = new Completer/*<T>*/.sync();
- var onValue = (/*=T*/ value) {
+ static Future<T> any<T>(Iterable<Future<T>> futures) {
+ var completer = new Completer<T>.sync();
+ var onValue = (T value) {
if (!completer.isCompleted) completer.complete(value);
};
var onError = (error, stack) {
@@ -363,18 +427,19 @@ abstract class Future<T> {
}
/**
- * Perform an async operation repeatedly until it returns `false`.
+ * Performs an async operation repeatedly until it returns `false`.
*
- * Runs [f] repeatedly, starting the next iteration only when the [Future]
- * returned by [f] completes to `true`. Returns a [Future] that completes once
- * [f] returns `false`.
+ * The function [f] is called repeatedly while it returns either the [bool]
+ * value `true` or a [Future] which completes with the value `true`.
*
- * The return values of all [Future]s are discarded. Any errors will cause the
- * iteration to stop and will be piped through the returned [Future].
+ * If a call to [f] returns `false` or a [Future] that completes to `false`,
+ * iteration ends and the future returned by [doWhile] is completed.
+ *
+ * If a future returned by [f] completes with an error, iteration ends and
+ * the future returned by [doWhile] completes with the same error.
*
- * The function [f] may return either a [bool] or a [Future] that completes to
- * a [bool]. If it returns a non-[Future], iteration continues immediately.
- * Otherwise it waits for the returned [Future] to complete.
+ * The [f] function must return either a `bool` value or a [Future] completing
+ * with a `bool` value.
*/
static Future doWhile(f()) {
_Future doneSignal = new _Future();
@@ -432,7 +497,7 @@ abstract class Future<T> {
* with a `test` parameter, instead of handling both value and error in a
* single [then] call.
*/
- Future/*<S>*/ then/*<S>*/(onValue(T value), { Function onError });
+ Future<S> then<S>(FutureOr<S> onValue(T value), { Function onError });
/**
* Handles errors emitted by this [Future].
@@ -495,7 +560,7 @@ abstract class Future<T> {
// `isCheck` we should also expect functions that take a specific argument.
// Note: making `catchError` return a `Future<T>` in non-strong mode could be
// a breaking change.
- Future/*<T>*/ catchError(Function onError,
+ Future<T> catchError(Function onError,
{bool test(Object error)});
/**
« no previous file with comments | « pkg/dev_compiler/test/codegen_test.dart ('k') | pkg/dev_compiler/tool/input_sdk/lib/async/future_impl.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698