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

Side by Side Diff: sdk/lib/async/future_impl.dart

Issue 702413002: Revert "Convert _propagateToListeners to using an external stack instead of recursion." (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 1 month 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | sdk/lib/async/zone.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 part of dart.async; 5 part of dart.async;
6 6
7 /** The onValue and onError handlers return either a value or a future */ 7 /** The onValue and onError handlers return either a value or a future */
8 typedef dynamic _FutureOnValue<T>(T value); 8 typedef dynamic _FutureOnValue<T>(T value);
9 /** Test used by [Future.catchError] to handle skip some errors. */ 9 /** Test used by [Future.catchError] to handle skip some errors. */
10 typedef bool _FutureErrorTest(var error); 10 typedef bool _FutureErrorTest(var error);
11 /** Used by [WhenFuture]. */ 11 /** Used by [WhenFuture]. */
12 typedef _FutureAction(); 12 typedef _FutureAction();
13 13
14 const bool _GUARDED = true;
15 const bool _UNGUARDED = false;
16
17 abstract class _Completer<T> implements Completer<T> { 14 abstract class _Completer<T> implements Completer<T> {
18 final _Future<T> future = new _Future<T>(); 15 final _Future<T> future = new _Future<T>();
19 16
20 void complete([value]); 17 void complete([value]);
21 18
22 void completeError(Object error, [StackTrace stackTrace]) { 19 void completeError(Object error, [StackTrace stackTrace]) {
23 error = _nonNullError(error); 20 error = _nonNullError(error);
24 if (!future._mayComplete) throw new StateError("Future already completed"); 21 if (!future._mayComplete) throw new StateError("Future already completed");
25 AsyncError replacement = Zone.current.errorCallback(error, stackTrace); 22 AsyncError replacement = Zone.current.errorCallback(error, stackTrace);
26 if (replacement != null) { 23 if (replacement != null) {
(...skipping 240 matching lines...) Expand 10 before | Expand all | Expand 10 after
267 264
268 void _setError(Object error, StackTrace stackTrace) { 265 void _setError(Object error, StackTrace stackTrace) {
269 _setErrorObject(new AsyncError(error, stackTrace)); 266 _setErrorObject(new AsyncError(error, stackTrace));
270 } 267 }
271 268
272 void _addListener(_FutureListener listener) { 269 void _addListener(_FutureListener listener) {
273 assert(listener._nextListener == null); 270 assert(listener._nextListener == null);
274 if (_isComplete) { 271 if (_isComplete) {
275 // Handle late listeners asynchronously. 272 // Handle late listeners asynchronously.
276 _zone.scheduleMicrotask(() { 273 _zone.scheduleMicrotask(() {
277 _propagateToFutures(this, listener, _UNGUARDED); 274 _propagateToListeners(this, listener);
278 }); 275 });
279 } else { 276 } else {
280 listener._nextListener = _resultOrListeners; 277 listener._nextListener = _resultOrListeners;
281 _resultOrListeners = listener; 278 _resultOrListeners = listener;
282 } 279 }
283 } 280 }
284 281
285 _FutureListener _removeListeners() { 282 _FutureListener _removeListeners() {
286 // Reverse listeners before returning them, so the resulting list is in 283 // Reverse listeners before returning them, so the resulting list is in
287 // subscription order. 284 // subscription order.
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
324 // Take the value (when completed) of source and complete target with that 321 // Take the value (when completed) of source and complete target with that
325 // value (or error). This function expects that source is a _Future. 322 // value (or error). This function expects that source is a _Future.
326 static void _chainCoreFuture(_Future source, _Future target) { 323 static void _chainCoreFuture(_Future source, _Future target) {
327 assert(!target._isComplete); 324 assert(!target._isComplete);
328 assert(source is _Future); 325 assert(source is _Future);
329 326
330 // Mark the target as chained (and as such half-completed). 327 // Mark the target as chained (and as such half-completed).
331 target._isChained = true; 328 target._isChained = true;
332 _FutureListener listener = new _FutureListener.chain(target); 329 _FutureListener listener = new _FutureListener.chain(target);
333 if (source._isComplete) { 330 if (source._isComplete) {
334 _propagateToFutures(source, listener, _GUARDED); 331 _propagateToListeners(source, listener);
335 } else { 332 } else {
336 source._addListener(listener); 333 source._addListener(listener);
337 } 334 }
338 } 335 }
339 336
340 void _complete(value) { 337 void _complete(value) {
341 assert(!_isComplete); 338 assert(!_isComplete);
342 if (value is Future) { 339 if (value is Future) {
343 if (value is _Future) { 340 if (value is _Future) {
344 _chainCoreFuture(value, this); 341 _chainCoreFuture(value, this);
345 } else { 342 } else {
346 _chainForeignFuture(value, this); 343 _chainForeignFuture(value, this);
347 } 344 }
348 } else { 345 } else {
349 _FutureListener listeners = _removeListeners(); 346 _FutureListener listeners = _removeListeners();
350 _setValue(value); 347 _setValue(value);
351 _propagateToFutures(this, listeners, _GUARDED); 348 _propagateToListeners(this, listeners);
352 } 349 }
353 } 350 }
354 351
355 void _completeWithValue(value) { 352 void _completeWithValue(value) {
356 assert(!_isComplete); 353 assert(!_isComplete);
357 assert(value is! Future); 354 assert(value is! Future);
358 355
359 _FutureListener listeners = _removeListeners(); 356 _FutureListener listeners = _removeListeners();
360 _setValue(value); 357 _setValue(value);
361 _propagateToFutures(this, listeners, _GUARDED); 358 _propagateToListeners(this, listeners);
362 } 359 }
363 360
364 void _completeError(error, [StackTrace stackTrace]) { 361 void _completeError(error, [StackTrace stackTrace]) {
365 assert(!_isComplete); 362 assert(!_isComplete);
366 363
367 _FutureListener listeners = _removeListeners(); 364 _FutureListener listeners = _removeListeners();
368 _setError(error, stackTrace); 365 _setError(error, stackTrace);
369 _propagateToFutures(this, listeners, _GUARDED); 366 _propagateToListeners(this, listeners);
370 } 367 }
371 368
372 void _asyncComplete(value) { 369 void _asyncComplete(value) {
373 assert(!_isComplete); 370 assert(!_isComplete);
374 // Two corner cases if the value is a future: 371 // Two corner cases if the value is a future:
375 // 1. the future is already completed and an error. 372 // 1. the future is already completed and an error.
376 // 2. the future is not yet completed but might become an error. 373 // 2. the future is not yet completed but might become an error.
377 // The first case means that we must not immediately complete the Future, 374 // The first case means that we must not immediately complete the Future,
378 // as our code would immediately start propagating the error without 375 // as our code would immediately start propagating the error without
379 // giving the time to install error-handlers. 376 // giving the time to install error-handlers.
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
419 void _asyncCompleteError(error, StackTrace stackTrace) { 416 void _asyncCompleteError(error, StackTrace stackTrace) {
420 assert(!_isComplete); 417 assert(!_isComplete);
421 418
422 _markPendingCompletion(); 419 _markPendingCompletion();
423 _zone.scheduleMicrotask(() { 420 _zone.scheduleMicrotask(() {
424 _completeError(error, stackTrace); 421 _completeError(error, stackTrace);
425 }); 422 });
426 } 423 }
427 424
428 /** 425 /**
429 * Stack implemented by linked list of [_PendingFutureListeners].
430 *
431 * Each `_PendingFutureListeners` have on source future and one or more
432 * listeners on that future (linked internally through
433 * [_FutureListener._nextListener]).
434 *
435 * While propagating future results to listeners, pending listeners are
436 * stored on this stack.
437 */
438 static _PendingFutureListeners _pendingFutureListeners = null;
439
440 /**
441 * Handle an uncaught async error.
442 *
443 * If the [guarded] flag is `true`, or the future's zone has an error
444 * handler, the uncaught error is passed to the zone's error handler.
445 * Otherwise, the uncaught error is thrown immediately, and is expected
446 * to propagate to the event loop. (If it can't propagate to the event
447 * loop, `guarded` should be true).
448 */
449 static void _throwUncaughtError(_Future source, bool guarded) {
450 assert(source._hasError);
451 AsyncError asyncError = source._error;
452 Zone zone = source._zone;
453 if (guarded || !identical(zone.errorZone, _ROOT_ZONE)) {
454 zone.handleUncaughtError(asyncError.error, asyncError.stackTrace);
455 if (_pendingFutureListeners != null) {
456 _schedulePriorityAsyncCallback(_propagateToFutures);
457 }
458 return;
459 }
460 if (_pendingFutureListeners != null) {
461 _schedulePriorityAsyncCallback(_propagateToFutures);
462 }
463 throw new _UncaughtAsyncError(asyncError.error, asyncError.stackTrace);
464 }
465
466 /**
467 * Propagates the value/error of [source] to its [listeners], executing the 426 * Propagates the value/error of [source] to its [listeners], executing the
468 * listeners' callbacks. 427 * listeners' callbacks.
469 *
470 * The [guarded] flag should be set when the function isn't being called in
471 * tail position of an event, or if simply throwing an uncaught error is
472 * otherwise not acceptable.
473 *
474 * Parameters are optional to allow using [_propagateToFutures] directly
475 * as a scheduled function. In that case, it takes its sources from
476 * [_pendingFutureListeners].
477 */ 428 */
478 static void _propagateToFutures([_Future source, 429 static void _propagateToListeners(_Future source, _FutureListener listeners) {
479 _FutureListener listeners,
480 bool guarded = _UNGUARDED]) {
481 while (true) { 430 while (true) {
482 if (source == null) { 431 assert(source._isComplete);
483 // Pop source and listeners from _pendingFutureListeners. 432 bool hasError = source._hasError;
484 // This always sets `listeners` to be a single listener. 433 if (listeners == null) {
485 if (_pendingFutureListeners == null) return; 434 if (hasError) {
486 _PendingFutureListeners pending = _pendingFutureListeners; 435 AsyncError asyncError = source._error;
487 // Read top-most source and listener. 436 source._zone.handleUncaughtError(
488 source = pending.source; 437 asyncError.error, asyncError.stackTrace);
489 listeners = pending.listeners;
490 // Remove the top-most listener. If it's the last listener for
491 // source, go to the next _PendingFutureListeners block.
492 if (listeners != null && listeners._nextListener != null) {
493 pending.listeners = listeners._nextListener;
494 listeners._nextListener = null;
495 } else {
496 _pendingFutureListeners = pending.next;
497 } 438 }
498 } else { 439 return;
499 // Check if there are zero listeners, or more than one listener.
500 assert(source._isComplete);
501 if (listeners == null) {
502 // If zero listeners, and source has an error, consider the error
503 // uncaught.
504 if (source._hasError) {
505 _throwUncaughtError(source, guarded);
506 return;
507 }
508 if (_pendingFutureListeners == null) return;
509 source = null;
510 continue;
511 } else if (listeners._nextListener != null) {
512 // Usually futures only have one listener.
513 // If they have several, we put the rest on the pending listener
514 // stack and handle them later.
515 _pendingFutureListeners =
516 new _PendingFutureListeners(source, listeners._nextListener,
517 _pendingFutureListeners);
518 listeners._nextListener = null;
519 }
520 } 440 }
521 assert(source != null); 441 // Usually futures only have one listener. If they have several, we
522 assert(listeners != null); 442 // call handle them separately in recursive calls, continuing
523 assert(listeners._nextListener == null); 443 // here only when there is only one listener left.
444 while (listeners._nextListener != null) {
445 _FutureListener listener = listeners;
446 listeners = listener._nextListener;
447 listener._nextListener = null;
448 _propagateToListeners(source, listener);
449 }
524 _FutureListener listener = listeners; 450 _FutureListener listener = listeners;
525
526 bool hasError = source._hasError;
527 // Do the actual propagation. 451 // Do the actual propagation.
528 // Set initial state of listenerHasError and listenerValueOrError. These 452 // Set initial state of listenerHasValue and listenerValueOrError. These
529 // variables are updated, with the outcome of potential callbacks. 453 // variables are updated, with the outcome of potential callbacks.
530 bool listenerHasError = hasError; 454 bool listenerHasValue = true;
531 final sourceValue = hasError ? source._error : source._value; 455 final sourceValue = hasError ? null : source._value;
532 var listenerValueOrError = sourceValue; 456 var listenerValueOrError = sourceValue;
533 // Set to true if a whenComplete needs to wait for a future. 457 // Set to true if a whenComplete needs to wait for a future.
534 // The whenComplete action will resume the propagation by itself. 458 // The whenComplete action will resume the propagation by itself.
535 bool isPropagationAborted = false; 459 bool isPropagationAborted = false;
536 // TODO(floitsch): mark the listener as pending completion. Currently 460 // TODO(floitsch): mark the listener as pending completion. Currently
537 // we can't do this, since the markPendingCompletion verifies that 461 // we can't do this, since the markPendingCompletion verifies that
538 // the future is not already marked (or chained). 462 // the future is not already marked (or chained).
539 // Only if we either have an error or callbacks, go into this, somewhat 463 // Only if we either have an error or callbacks, go into this, somewhat
540 // expensive, branch. Here we'll enter/leave the zone. Many futures 464 // expensive, branch. Here we'll enter/leave the zone. Many futures
541 // doesn't have callbacks, so this is a significant optimization. 465 // doesn't have callbacks, so this is a significant optimization.
542 if (hasError || (listener.handlesValue || listener.handlesComplete)) { 466 if (hasError || (listener.handlesValue || listener.handlesComplete)) {
543 Zone zone = listener._zone; 467 Zone zone = listener._zone;
468 if (hasError && !source._zone.inSameErrorZone(zone)) {
469 // Don't cross zone boundaries with errors.
470 AsyncError asyncError = source._error;
471 source._zone.handleUncaughtError(
472 asyncError.error, asyncError.stackTrace);
473 return;
474 }
475
476 Zone oldZone;
477 if (!identical(Zone.current, zone)) {
478 // Change zone if it's not current.
479 oldZone = Zone._enter(zone);
480 }
481
482 bool handleValueCallback() {
483 try {
484 listenerValueOrError = zone.runUnary(listener._onValue,
485 sourceValue);
486 return true;
487 } catch (e, s) {
488 listenerValueOrError = new AsyncError(e, s);
489 return false;
490 }
491 }
544 492
545 void handleError() { 493 void handleError() {
546 assert(listener.handlesError);
547 AsyncError asyncError = source._error; 494 AsyncError asyncError = source._error;
548 bool matchesTest = true; 495 bool matchesTest = true;
549 if (listener.hasErrorTest) { 496 if (listener.hasErrorTest) {
550 _FutureErrorTest test = listener._errorTest; 497 _FutureErrorTest test = listener._errorTest;
551 try { 498 try {
552 matchesTest = zone.runUnary(test, asyncError.error); 499 matchesTest = zone.runUnary(test, asyncError.error);
553 } catch (e, s) { 500 } catch (e, s) {
554 listenerValueOrError = identical(asyncError.error, e) ? 501 listenerValueOrError = identical(asyncError.error, e) ?
555 asyncError : new AsyncError(e, s); 502 asyncError : new AsyncError(e, s);
556 listenerHasError = true; 503 listenerHasValue = false;
557 return; 504 return;
558 } 505 }
559 } 506 }
560 if (matchesTest) { 507 Function errorCallback = listener._onError;
561 Function errorCallback = listener._onError; 508 if (matchesTest && errorCallback != null) {
562 assert(errorCallback != null);
563 try { 509 try {
564 if (errorCallback is ZoneBinaryCallback) { 510 if (errorCallback is ZoneBinaryCallback) {
565 listenerValueOrError = zone.runBinary(errorCallback, 511 listenerValueOrError = zone.runBinary(errorCallback,
566 asyncError.error, 512 asyncError.error,
567 asyncError.stackTrace); 513 asyncError.stackTrace);
568 } else { 514 } else {
569 listenerValueOrError = zone.runUnary(errorCallback, 515 listenerValueOrError = zone.runUnary(errorCallback,
570 asyncError.error); 516 asyncError.error);
571 } 517 }
572 } catch (e, s) { 518 } catch (e, s) {
573 listenerValueOrError = identical(asyncError.error, e) ? 519 listenerValueOrError = identical(asyncError.error, e) ?
574 asyncError : new AsyncError(e, s); 520 asyncError : new AsyncError(e, s);
575 listenerHasError = true; 521 listenerHasValue = false;
576 return; 522 return;
577 } 523 }
578 listenerHasError = false; 524 listenerHasValue = true;
525 } else {
526 // Copy over the error from the source.
527 listenerValueOrError = asyncError;
528 listenerHasValue = false;
579 } 529 }
580 } 530 }
581 531
582 void handleWhenCompleteCallback() { 532 void handleWhenCompleteCallback() {
583 var completeResult; 533 var completeResult;
584 try { 534 try {
585 completeResult = zone.run(listener._whenCompleteAction); 535 completeResult = zone.run(listener._whenCompleteAction);
586 } catch (e, s) { 536 } catch (e, s) {
587 if (hasError && identical(source._error.error, e)) { 537 if (hasError && identical(source._error.error, e)) {
588 listenerValueOrError = source._error; 538 listenerValueOrError = source._error;
589 } else { 539 } else {
590 listenerValueOrError = new AsyncError(e, s); 540 listenerValueOrError = new AsyncError(e, s);
591 } 541 }
592 listenerHasError = true; 542 listenerHasValue = false;
593 return; 543 return;
594 } 544 }
595 if (completeResult is Future) { 545 if (completeResult is Future) {
596 _Future result = listener.result; 546 _Future result = listener.result;
597 result._isChained = true; 547 result._isChained = true;
598 isPropagationAborted = true; 548 isPropagationAborted = true;
599 final _Future originalSource = source;
600 completeResult.then((ignored) { 549 completeResult.then((ignored) {
601 _propagateToFutures(originalSource, 550 _propagateToListeners(source, new _FutureListener.chain(result));
602 new _FutureListener.chain(result),
603 _UNGUARDED);
604 }, onError: (error, [stackTrace]) { 551 }, onError: (error, [stackTrace]) {
605 // When there is an error, we have to make the error the new 552 // When there is an error, we have to make the error the new
606 // result of the current listener. 553 // result of the current listener.
607 if (completeResult is! _Future) { 554 if (completeResult is! _Future) {
608 // This should be a rare case. 555 // This should be a rare case.
609 completeResult = new _Future(); 556 completeResult = new _Future();
610 completeResult._setError(error, stackTrace); 557 completeResult._setError(error, stackTrace);
611 } 558 }
612 _propagateToFutures(completeResult, 559 _propagateToListeners(completeResult,
613 new _FutureListener.chain(result), 560 new _FutureListener.chain(result));
614 _UNGUARDED);
615 }); 561 });
616 } 562 }
617 } 563 }
618 564
619 Zone oldZone = Zone._enter(zone);
620
621 if (!hasError) { 565 if (!hasError) {
622 if (listener.handlesValue) { 566 if (listener.handlesValue) {
623 // Run try/catch in separate function to help compilers. 567 listenerHasValue = handleValueCallback();
624 () {
625 try {
626 listenerValueOrError = zone.runUnary(listener._onValue,
627 sourceValue);
628 listenerHasError = false;
629 } catch (e, s) {
630 listenerValueOrError = new AsyncError(e, s);
631 listenerHasError = true;
632 }
633 }();
634 assert(!listener.handlesComplete);
635 } else if (listener.handlesComplete) {
636 // Complete-listeners are distinct from value/error handlers,
637 // so no need to check for a complete handler if it is an error
638 // handler.
639 handleWhenCompleteCallback();
640 } 568 }
641 } else { 569 } else {
642 if (!source._zone.inSameErrorZone(zone)) { 570 handleError();
643 // Don't cross zone boundaries with errors.
644 Zone._leave(oldZone);
645 _throwUncaughtError(source, guarded);
646 return;
647 }
648 if (listener.handlesError) {
649 handleError();
650 assert(!listener.handlesComplete);
651 } else if (listener.handlesComplete) {
652 handleWhenCompleteCallback();
653 }
654 } 571 }
572 if (listener.handlesComplete) {
573 handleWhenCompleteCallback();
574 }
575 // If we changed zone, oldZone will not be null.
576 if (oldZone != null) Zone._leave(oldZone);
655 577
656 Zone._leave(oldZone); 578 if (isPropagationAborted) return;
657
658 if (isPropagationAborted) {
659 // Don't use the value in listenerValueOrError - the whenComplete
660 // handler is handling that result.
661 if (_pendingFutureListeners == null) return;
662 source = null;
663 continue;
664 }
665 // If the listener's value is a future we need to chain it. Note that 579 // If the listener's value is a future we need to chain it. Note that
666 // this can only happen if there is a callback. Since 'is' checks 580 // this can only happen if there is a callback. Since 'is' checks
667 // can be expensive, we're trying to avoid it. 581 // can be expensive, we're trying to avoid it.
668 if (!listenerHasError && 582 if (listenerHasValue &&
669 !identical(sourceValue, listenerValueOrError) && 583 !identical(sourceValue, listenerValueOrError) &&
670 listenerValueOrError is Future) { 584 listenerValueOrError is Future) {
671 Future chainSource = listenerValueOrError; 585 Future chainSource = listenerValueOrError;
672 // Shortcut if the chain-source is already completed. Just continue 586 // Shortcut if the chain-source is already completed. Just continue
673 // the loop. 587 // the loop.
674 _Future result = listener.result; 588 _Future result = listener.result;
675 if (chainSource is _Future) { 589 if (chainSource is _Future) {
676 if (chainSource._isComplete) { 590 if (chainSource._isComplete) {
677 // Propagate the value (simulating a tail call). 591 // propagate the value (simulating a tail call).
678 result._isChained = true; 592 result._isChained = true;
679 source = chainSource; 593 source = chainSource;
680 listeners = new _FutureListener.chain(result); 594 listeners = new _FutureListener.chain(result);
681 continue; 595 continue;
682 } else { 596 } else {
683 _chainCoreFuture(chainSource, result); 597 _chainCoreFuture(chainSource, result);
684 } 598 }
685 } else { 599 } else {
686 _chainForeignFuture(chainSource, result); 600 _chainForeignFuture(chainSource, result);
687 } 601 }
688 if (_pendingFutureListeners == null) return; 602 return;
689 source = null;
690 continue;
691 } 603 }
692 } 604 }
693 // Complete the future waiting for the result.
694 _Future result = listener.result; 605 _Future result = listener.result;
695 _FutureListener resultListeners = result._removeListeners(); 606 listeners = result._removeListeners();
696 if (!listenerHasError) { 607 if (listenerHasValue) {
697 result._setValue(listenerValueOrError); 608 result._setValue(listenerValueOrError);
698 } else { 609 } else {
699 AsyncError asyncError = listenerValueOrError; 610 AsyncError asyncError = listenerValueOrError;
700 result._setErrorObject(asyncError); 611 result._setErrorObject(asyncError);
701 } 612 }
702 // Prepare for next round. 613 // Prepare for next round.
703 source = result; 614 source = result;
704 listeners = resultListeners;
705 } 615 }
706 } 616 }
707 617
708 Future timeout(Duration timeLimit, {onTimeout()}) { 618 Future timeout(Duration timeLimit, {onTimeout()}) {
709 if (_isComplete) return new _Future.immediate(this); 619 if (_isComplete) return new _Future.immediate(this);
710 _Future result = new _Future(); 620 _Future result = new _Future();
711 Timer timer; 621 Timer timer;
712 if (onTimeout == null) { 622 if (onTimeout == null) {
713 timer = new Timer(timeLimit, () { 623 timer = new Timer(timeLimit, () {
714 result._completeError(new TimeoutException("Future not completed", 624 result._completeError(new TimeoutException("Future not completed",
(...skipping 17 matching lines...) Expand all
732 } 642 }
733 }, onError: (e, s) { 643 }, onError: (e, s) {
734 if (timer.isActive) { 644 if (timer.isActive) {
735 timer.cancel(); 645 timer.cancel();
736 result._completeError(e, s); 646 result._completeError(e, s);
737 } 647 }
738 }); 648 });
739 return result; 649 return result;
740 } 650 }
741 } 651 }
742
743 class _PendingFutureListeners {
744 final _Future source;
745 final _PendingFutureListeners next;
746 _FutureListener listeners;
747 _PendingFutureListeners(this.source, this.listeners, this.next);
748 }
OLDNEW
« no previous file with comments | « no previous file | sdk/lib/async/zone.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698