@@ -327,6 +327,9 @@ class _Future<T> implements Future<T> {
327327 // This constructor is used by async/await.
328328 _Future () : _zone = Zone ._current;
329329
330+ // Empty `_Future` in a given zone.
331+ _Future .zone (this ._zone);
332+
330333 // Constructor used by [Future.value].
331334 _Future .immediate (FutureOr <T > result) : _zone = Zone ._current {
332335 _asyncComplete (result);
@@ -397,11 +400,18 @@ class _Future<T> implements Future<T> {
397400 }
398401
399402 void _ignore () {
400- _Future <Object ?> source = this ;
401- while (source._isChained) {
402- source = source._chainSource;
403+ _state | = _stateIgnoreError;
404+ if (_isChained) {
405+ // Mark chain source. If it has no listeners at all, then neither
406+ // does this future. (But this may suppress errors on other futures
407+ // with the same chain source and no listeners, which haven't been
408+ // ignored.)
409+ _Future <Object ?> source = this ;
410+ do {
411+ source = source._chainSource;
412+ } while (source._isChained);
413+ source._state | = _stateIgnoreError;
403414 }
404- source._state | = _stateIgnoreError;
405415 }
406416
407417 Future <T > catchError (Function onError, {bool test (Object error)? }) {
@@ -573,7 +583,7 @@ class _Future<T> implements Future<T> {
573583 /// Completes this future with the result of [source] .
574584 ///
575585 /// The [source] future should not be a [_Future] , use
576- /// [_chainCoreFutureSync ] for those.
586+ /// [_chainCoreFuture ] for those.
577587 ///
578588 /// Since [source] is an unknown [Future] , it's interacted with
579589 /// through [Future.then] , which is required to be asynchronous.
@@ -613,37 +623,7 @@ class _Future<T> implements Future<T> {
613623 /// propagated to the target future's listeners.
614624 /// If the source future is not completed, the target future is made
615625 /// to listen for its completion.
616- static void _chainCoreFutureSync (_Future source, _Future target) {
617- assert (target._mayAddListener); // Not completed, not already chained.
618- while (source._isChained) {
619- source = source._chainSource;
620- }
621- if (identical (source, target)) {
622- target._asyncCompleteError (
623- ArgumentError .value (
624- source, null , "Cannot complete a future with itself" ),
625- StackTrace .current);
626- return ;
627- }
628- source._state | = target._state & _stateIgnoreError;
629- if (source._isComplete) {
630- _FutureListener ? listeners = target._removeListeners ();
631- target._cloneResult (source);
632- _propagateToListeners (target, listeners);
633- } else {
634- _FutureListener ? listeners = target._resultOrListeners;
635- target._setChained (source);
636- source._prependListeners (listeners);
637- }
638- }
639-
640- /// Asynchronously completes a [target] future with a [source] future.
641- ///
642- /// If the [source] future is already completed, its result is
643- /// asynchronously propagated to the [target] future's listeners.
644- /// If the [source] future is not completed, the [target] future is made
645- /// to listen for its completion.
646- static void _chainCoreFutureAsync (_Future source, _Future target) {
626+ static void _chainCoreFuture (_Future source, _Future target, bool sync ) {
647627 assert (target._mayAddListener); // Not completed, not already chained.
648628 while (source._isChained) {
649629 source = source._chainSource;
@@ -655,26 +635,32 @@ class _Future<T> implements Future<T> {
655635 StackTrace .current);
656636 return ;
657637 }
638+ var ignoreError = target._state & _stateIgnoreError;
639+ source._state | = ignoreError;
658640 if (! source._isComplete) {
659641 // Chain immediately if the source is not complete.
660- // This won't call any listeners.
642+ // This won't call any listeners, whether completing sync or async .
661643 _FutureListener ? listeners = target._resultOrListeners;
662644 target._setChained (source);
663645 source._prependListeners (listeners);
664646 return ;
665647 }
666648
667- // Complete a value synchronously, if no-one is listening.
668- // This won't call any listeners.
669- if (! source._hasError && target._resultOrListeners == null ) {
649+ if (sync ||
650+ (target._resultOrListeners == null &&
651+ (! source._hasError || ignoreError != 0 ))) {
652+ // Complete synchronously when allowed.
653+ // If no-one is listening this won't call any listeners synchronously.
654+ // Do delay un-ignored errors to give time to add listeners.
655+ _FutureListener ? listeners = target._removeListeners ();
670656 target._cloneResult (source);
657+ _propagateToListeners (target, listeners);
671658 return ;
672659 }
673-
674660 // Otherwise delay the chaining to avoid any synchronous callbacks.
675661 target._setPendingComplete ();
676662 target._zone.scheduleMicrotask (() {
677- _chainCoreFutureSync (source, target);
663+ _chainCoreFuture (source, target, _allowCompleteSync );
678664 });
679665 }
680666
@@ -688,7 +674,7 @@ class _Future<T> implements Future<T> {
688674 assert (! _isComplete);
689675 if (value is Future <T >) {
690676 if (value is _Future <T >) {
691- _chainCoreFutureSync (value, this );
677+ _chainCoreFuture (value, this , _allowCompleteSync );
692678 } else {
693679 _chainForeignFuture (value);
694680 }
@@ -707,6 +693,16 @@ class _Future<T> implements Future<T> {
707693 _propagateToListeners (this , listeners);
708694 }
709695
696+ void _completeWithResultOf (_Future <Object ?> source) {
697+ assert (source._isComplete);
698+ if (source._hasError && ! _zone.inSameErrorZone (source._zone)) {
699+ return ;
700+ }
701+ _FutureListener ? listeners = _removeListeners ();
702+ _cloneResult (source);
703+ _propagateToListeners (this , listeners);
704+ }
705+
710706 void _completeError (Object error, StackTrace stackTrace) {
711707 assert (! _isComplete);
712708
@@ -786,7 +782,7 @@ class _Future<T> implements Future<T> {
786782 assert (_mayComplete);
787783 if (value is _Future <T >) {
788784 // Chain ensuring that we don't complete synchronously.
789- _chainCoreFutureAsync (value, this );
785+ _chainCoreFuture (value, this , _requireCompleteAsync );
790786 return ;
791787 }
792788 // Just listen on the foreign future. This guarantees an async delay.
@@ -892,7 +888,13 @@ class _Future<T> implements Future<T> {
892888 // before knowing if it's an error or we should use the result
893889 // of source.
894890 var originalSource = source;
895- listenerValueOrError = completeResult.then ((_) => originalSource);
891+ var joinedResult = source._newFutureWithSameType ();
892+ completeResult.then <void >((_) {
893+ joinedResult._completeWithResultOf (originalSource);
894+ }, onError: (Object e, StackTrace s) {
895+ joinedResult._completeError (e, s);
896+ });
897+ listenerValueOrError = joinedResult;
896898 listenerHasError = false ;
897899 }
898900 }
@@ -954,7 +956,7 @@ class _Future<T> implements Future<T> {
954956 source = chainSource;
955957 continue ;
956958 } else {
957- _chainCoreFutureSync (chainSource, result);
959+ _chainCoreFuture (chainSource, result, _allowCompleteSync );
958960 }
959961 } else {
960962 result._chainForeignFuture (chainSource);
@@ -976,6 +978,12 @@ class _Future<T> implements Future<T> {
976978 }
977979 }
978980
981+ /// New uncompleted future with same type.
982+ ///
983+ /// In same zone or other [zone] if specified.
984+ _Future <T > _newFutureWithSameType ([_Zone ? zone]) =>
985+ _Future <T >.zone (zone ?? _zone);
986+
979987 @pragma ("vm:entry-point" )
980988 Future <T > timeout (Duration timeLimit, {FutureOr <T > onTimeout ()? }) {
981989 if (_isComplete) return new _Future .immediate (this );
@@ -1041,3 +1049,7 @@ Function _registerErrorHandler(Function errorHandler, Zone zone) {
10411049 "Error handler must accept one Object or one Object and a StackTrace"
10421050 " as arguments, and return a value of the returned future's type" );
10431051}
1052+
1053+ // Names for positional arguments to _chainCoreFuture.
1054+ const _allowCompleteSync = true ;
1055+ const _requireCompleteAsync = false ;
0 commit comments