Make sure that _StreamSinkImpl._isBound is kept up-to-date

There were two situations where this could get into a bad state:

* If the sink already had an error, _isBound would be set to true and
  never unset. This is fixed by not setting it at all if an error
  already exists.

* If _controllerCompleter completed to an error, _isBound would never
  get set back to false. This is fixed by refactoring the code so that
  the appropriate whenComplete() is always run.

Change-Id: Ia511fa3e2345213ff8e56dc4fae6f397b84257d1
Reviewed-on: https://dart-review.googlesource.com/26981
Commit-Queue: Natalie Weizenbaum <nweiz@google.com>
Reviewed-by: Lasse R.H. Nielsen <lrn@google.com>
This commit is contained in:
Natalie Weizenbaum 2017-12-12 22:41:29 +00:00 committed by commit-bot@chromium.org
parent 0a289c8341
commit acdd2adbdf

View file

@ -180,19 +180,19 @@ class _StreamSinkImpl<T> implements StreamSink<T> {
if (_isBound) {
throw new StateError("StreamSink is already bound to a stream");
}
_isBound = true;
if (_hasError) return done;
// Wait for any sync operations to complete.
Future targetAddStream() {
return _target.addStream(stream).whenComplete(() {
_isBound = false;
});
}
if (_controllerInstance == null) return targetAddStream();
var future = _controllerCompleter.future;
_controllerInstance.close();
return future.then((_) => targetAddStream());
_isBound = true;
var future = _controllerCompleter == null
? _target.addStream(stream)
: _controllerCompleter.future.then((_) => _target.addStream(stream));
_controllerInstance?.close();
// Wait for any pending events in [_controller] to be dispatched before
// adding [stream].
return future.whenComplete(() {
_isBound = false;
});
}
Future flush() {