| Index: sdk/lib/async/future_impl.dart | 
| diff --git a/sdk/lib/async/future_impl.dart b/sdk/lib/async/future_impl.dart | 
| index ad7b9bdc86818cfdaa6e15532e5bea2293e352c7..748a2beef68e78c8f7dd62b9c9cf16129d2b7397 100644 | 
| --- a/sdk/lib/async/future_impl.dart | 
| +++ b/sdk/lib/async/future_impl.dart | 
| @@ -6,7 +6,6 @@ part of dart.async; | 
|  | 
| /** The onValue and onError handlers return either a value or a future */ | 
| typedef dynamic _FutureOnValue<T>(T value); | 
| -typedef dynamic _FutureOnError(error); | 
| /** Test used by [Future.catchError] to handle skip some errors. */ | 
| typedef bool _FutureErrorTest(var error); | 
| /** Used by [WhenFuture]. */ | 
| @@ -130,12 +129,12 @@ class _Future<T> implements Future<T> { | 
| // fields of which 2 are always null. | 
| final _FutureOnValue _onValueCallback; | 
| final _FutureErrorTest _errorTestCallback; | 
| -  final _FutureOnError _onErrorCallback; | 
| +  final Function _onErrorCallback; | 
| final _FutureAction _whenCompleteActionCallback; | 
|  | 
| _FutureOnValue get _onValue => _isChained ? null : _onValueCallback; | 
| _FutureErrorTest get _errorTest => _isChained ? null : _errorTestCallback; | 
| -  _FutureOnError get _onError => _isChained ? null : _onErrorCallback; | 
| +  Function get _onError => _isChained ? null : _onErrorCallback; | 
| _FutureAction get _whenCompleteAction | 
| => _isChained ? null : _whenCompleteActionCallback; | 
|  | 
| @@ -159,17 +158,18 @@ class _Future<T> implements Future<T> { | 
| _asyncCompleteError(error, stackTrace); | 
| } | 
|  | 
| -  _Future._then(onValueCallback(value), onErrorCallback(e)) | 
| +  _Future._then(onValueCallback(value), Function onErrorCallback) | 
| : _zone = Zone.current, | 
| _onValueCallback = Zone.current.registerUnaryCallback(onValueCallback), | 
| -        _onErrorCallback = Zone.current.registerUnaryCallback(onErrorCallback), | 
| +        _onErrorCallback = _registerErrorHandler(onErrorCallback, Zone.current), | 
| _errorTestCallback = null, | 
| _whenCompleteActionCallback = null; | 
|  | 
| -  _Future._catchError(onErrorCallback(e), bool errorTestCallback(e)) | 
| +  _Future._catchError(Function onErrorCallback, bool errorTestCallback(e)) | 
| : _zone = Zone.current, | 
| -      _onErrorCallback = Zone.current.registerUnaryCallback(onErrorCallback), | 
| -      _errorTestCallback = Zone.current.registerUnaryCallback(errorTestCallback), | 
| +      _onErrorCallback = _registerErrorHandler(onErrorCallback, Zone.current), | 
| +      _errorTestCallback = | 
| +          Zone.current.registerUnaryCallback(errorTestCallback), | 
| _onValueCallback = null, | 
| _whenCompleteActionCallback = null; | 
|  | 
| @@ -181,15 +181,15 @@ class _Future<T> implements Future<T> { | 
| _errorTestCallback = null, | 
| _onErrorCallback = null; | 
|  | 
| -  Future then(f(T value), { onError(error) }) { | 
| +  Future then(f(T value), { Function onError }) { | 
| _Future result; | 
| result = new _Future._then(f, onError); | 
| _addListener(result); | 
| return result; | 
| } | 
|  | 
| -  Future catchError(f(error), { bool test(error) }) { | 
| -    _Future result = new _Future._catchError(f, test); | 
| +  Future catchError(Function onError, { bool test(error) }) { | 
| +    _Future result = new _Future._catchError(onError, test); | 
| _addListener(result); | 
| return result; | 
| } | 
| @@ -212,7 +212,7 @@ class _Future<T> implements Future<T> { | 
| return _resultOrListeners; | 
| } | 
|  | 
| -  Object get _error { | 
| +  _AsyncError get _error { | 
| assert(_isComplete && _hasError); | 
| return _resultOrListeners; | 
| } | 
| @@ -223,10 +223,10 @@ class _Future<T> implements Future<T> { | 
| _resultOrListeners = value; | 
| } | 
|  | 
| -  void _setError(Object error) { | 
| +  void _setError(Object error, StackTrace stackTrace) { | 
| assert(!_isComplete);  // But may have a completion pending. | 
| _state = _ERROR; | 
| -    _resultOrListeners = error; | 
| +    _resultOrListeners = new _AsyncError(error, stackTrace); | 
| } | 
|  | 
| void _addListener(_Future listener) { | 
| @@ -275,9 +275,13 @@ class _Future<T> implements Future<T> { | 
| assert(target._isChained); | 
| target._complete(value); | 
| }, | 
| -        onError: (error) { | 
| +        // 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._isChained); | 
| -          target._completeError(error); | 
| +          target._completeError(error, stackTrace); | 
| }); | 
| } | 
| } | 
| @@ -311,7 +315,7 @@ class _Future<T> implements Future<T> { | 
| } | 
|  | 
| _Future listeners = _isChained ? null : _removeListeners(); | 
| -    _setError(error); | 
| +    _setError(error, stackTrace); | 
| _propagateToListeners(this, listeners); | 
| } | 
|  | 
| @@ -398,7 +402,9 @@ class _Future<T> implements Future<T> { | 
| if (!source._isComplete) return;  // Chained future. | 
| bool hasError = source._hasError; | 
| if (hasError && listeners == null) { | 
| -        source._zone.handleUncaughtError(source._error); | 
| +        _AsyncError asyncError = source._error; | 
| +        source._zone.handleUncaughtError( | 
| +            asyncError.error, asyncError.stackTrace); | 
| return; | 
| } | 
| if (listeners == null) return; | 
| @@ -411,7 +417,9 @@ class _Future<T> implements Future<T> { | 
| } | 
| if (hasError && !source._zone.inSameErrorZone(listener._zone)) { | 
| // Don't cross zone boundaries with errors. | 
| -        source._zone.handleUncaughtError(source._error); | 
| +        _AsyncError asyncError = source._error; | 
| +        source._zone.handleUncaughtError( | 
| +            asyncError.error, asyncError.stackTrace); | 
| return; | 
| } | 
| if (!identical(Zone.current, listener._zone)) { | 
| @@ -454,18 +462,21 @@ class _Future<T> implements Future<T> { | 
| listenerHasValue = true; | 
| } | 
| } else { | 
| -            Object error = source._error; | 
| +            _AsyncError asyncError = source._error; | 
| _FutureErrorTest test = listener._errorTest; | 
| bool matchesTest = true; | 
| if (test != null) { | 
| -              matchesTest = test(error); | 
| +              matchesTest = test(asyncError.error); | 
| } | 
| if (matchesTest && listener._onError != null) { | 
| -              listenerValueOrError = listener._onError(error); | 
| +              Function errorCallback = listener._onError; | 
| +              listenerValueOrError = _invokeErrorHandler(errorCallback, | 
| +                                                         asyncError.error, | 
| +                                                         asyncError.stackTrace); | 
| listenerHasValue = true; | 
| } else { | 
| // Copy over the error from the source. | 
| -              listenerValueOrError = error; | 
| +              listenerValueOrError = asyncError; | 
| listenerHasValue = false; | 
| } | 
| } | 
| @@ -477,13 +488,13 @@ class _Future<T> implements Future<T> { | 
| completeResult.then((ignored) { | 
| // Try again, but this time don't run the whenComplete callback. | 
| _propagateToListeners(source, listener); | 
| -              }, onError: (error) { | 
| +              }, onError: (error, [stackTrace]) { | 
| // When there is an error, we have to make the error the new | 
| // result of the current listener. | 
| if (completeResult is! _Future) { | 
| // This should be a rare case. | 
| completeResult = new _Future(); | 
| -                  completeResult._setError(error); | 
| +                  completeResult._setError(error, stackTrace); | 
| } | 
| _propagateToListeners(completeResult, listener); | 
| }); | 
| @@ -491,8 +502,13 @@ class _Future<T> implements Future<T> { | 
| } | 
| } | 
| } catch (e, s) { | 
| -          // Set the exception as error. | 
| -          listenerValueOrError = _asyncError(e, s); | 
| +          // Set the exception as error unless the error is the same as the | 
| +          // original one. | 
| +          if (hasError && identical(source._error.error, e)) { | 
| +            listenerValueOrError = source._error; | 
| +          } else { | 
| +            listenerValueOrError = new _AsyncError(_asyncError(e, s), s); | 
| +          } | 
| listenerHasValue = false; | 
| } | 
| }); | 
| @@ -518,7 +534,8 @@ class _Future<T> implements Future<T> { | 
| listener._setValue(listenerValueOrError); | 
| } else { | 
| listeners = listener._removeListeners(); | 
| -        listener._setError(listenerValueOrError); | 
| +        _AsyncError asyncError = listenerValueOrError; | 
| +        listener._setError(asyncError.error, asyncError.stackTrace); | 
| } | 
| // Prepare for next round. | 
| source = listener; | 
|  |