mirror of
https://github.com/dart-lang/sdk
synced 2024-10-14 09:22:12 +00:00
Reapply "Create _nullFuture and _falseFuture in the root zone."
Originally landed by https://dart-review.googlesource.com/c/sdk/+/49509 Reverted because an internal test is fragile and changes behavior when the bug is fixed. Change-Id: I8516082e5741547c46aa521a91826846dc101303 Reviewed-on: https://dart-review.googlesource.com/63743 Reviewed-by: Leaf Petersen <leafp@google.com> Commit-Queue: Leaf Petersen <leafp@google.com>
This commit is contained in:
parent
ce682638d9
commit
91ce347309
|
@ -34,6 +34,13 @@
|
||||||
* Re-enable `Iterable.whereType`. The method was disabled because code
|
* Re-enable `Iterable.whereType`. The method was disabled because code
|
||||||
was still being compiled in Dart 1 mode, and the function was
|
was still being compiled in Dart 1 mode, and the function was
|
||||||
error-prone when used in that code.
|
error-prone when used in that code.
|
||||||
|
* `dart:async`
|
||||||
|
* Changed an internal lazily-allocated reusable "null future" to always belong
|
||||||
|
to the root zone. This avoids race conditions where the first access to the
|
||||||
|
future determined which zone it would belong to. The zone is only used
|
||||||
|
for *scheduling* the callback of listeners, the listeners themselves will
|
||||||
|
run in the correct zone in any case.
|
||||||
|
Issue [#32556](http://dartbug.com/32556).
|
||||||
|
|
||||||
## 2.0.0-dev.67.0
|
## 2.0.0-dev.67.0
|
||||||
|
|
||||||
|
|
|
@ -148,10 +148,12 @@ abstract class FutureOr<T> {
|
||||||
*/
|
*/
|
||||||
abstract class Future<T> {
|
abstract class Future<T> {
|
||||||
/// A `Future<Null>` completed with `null`.
|
/// A `Future<Null>` completed with `null`.
|
||||||
static final _Future<Null> _nullFuture = new _Future<Null>.value(null);
|
static final _Future<Null> _nullFuture =
|
||||||
|
new _Future<Null>.zoneValue(null, Zone.root);
|
||||||
|
|
||||||
/// A `Future<bool>` completed with `false`.
|
/// A `Future<bool>` completed with `false`.
|
||||||
static final _Future<bool> _falseFuture = new _Future<bool>.value(false);
|
static final _Future<bool> _falseFuture =
|
||||||
|
new _Future<bool>.zoneValue(false, Zone.root);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a future containing the result of calling [computation]
|
* Creates a future containing the result of calling [computation]
|
||||||
|
|
|
@ -186,7 +186,7 @@ class _Future<T> implements Future<T> {
|
||||||
* Until the future is completed, the field may hold the zone that
|
* Until the future is completed, the field may hold the zone that
|
||||||
* listener callbacks used to create this future should be run in.
|
* listener callbacks used to create this future should be run in.
|
||||||
*/
|
*/
|
||||||
final Zone _zone = Zone.current;
|
final Zone _zone;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Either the result, a list of listeners or another future.
|
* Either the result, a list of listeners or another future.
|
||||||
|
@ -206,20 +206,24 @@ class _Future<T> implements Future<T> {
|
||||||
var _resultOrListeners;
|
var _resultOrListeners;
|
||||||
|
|
||||||
// This constructor is used by async/await.
|
// This constructor is used by async/await.
|
||||||
_Future();
|
_Future() : _zone = Zone.current;
|
||||||
|
|
||||||
_Future.immediate(FutureOr<T> result) {
|
_Future.immediate(FutureOr<T> result) : _zone = Zone.current {
|
||||||
_asyncComplete(result);
|
_asyncComplete(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
_Future.immediateError(var error, [StackTrace stackTrace]) {
|
/** Creates a future with the value and the specified zone. */
|
||||||
|
_Future.zoneValue(T value, this._zone) {
|
||||||
|
_setValue(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
_Future.immediateError(var error, [StackTrace stackTrace])
|
||||||
|
: _zone = Zone.current {
|
||||||
_asyncCompleteError(error, stackTrace);
|
_asyncCompleteError(error, stackTrace);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Creates a future that is already completed with the value. */
|
/** Creates a future that is already completed with the value. */
|
||||||
_Future.value(T value) {
|
_Future.value(T value) : this.zoneValue(value, Zone.current);
|
||||||
_setValue(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool get _mayComplete => _state == _stateIncomplete;
|
bool get _mayComplete => _state == _stateIncomplete;
|
||||||
bool get _isPendingComplete => _state == _statePendingComplete;
|
bool get _isPendingComplete => _state == _statePendingComplete;
|
||||||
|
|
36
tests/lib_2/async/null_future_zone_test.dart
Normal file
36
tests/lib_2/async/null_future_zone_test.dart
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
|
||||||
|
// for details. All rights reserved. Use of this source code is governed by a
|
||||||
|
// BSD-style license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
import "package:expect/expect.dart";
|
||||||
|
import "package:async_helper/async_helper.dart";
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
main() {
|
||||||
|
asyncStart(2);
|
||||||
|
() async {
|
||||||
|
var it = new StreamIterator(new Stream.fromIterable([]));
|
||||||
|
Expect.isFalse(await it.moveNext());
|
||||||
|
|
||||||
|
Future nullFuture;
|
||||||
|
Future falseFuture;
|
||||||
|
|
||||||
|
runZoned(() {
|
||||||
|
nullFuture = (new StreamController()..stream.listen(null).cancel()).done;
|
||||||
|
falseFuture = it.moveNext();
|
||||||
|
}, zoneSpecification: new ZoneSpecification(scheduleMicrotask:
|
||||||
|
(Zone self, ZoneDelegate parent, Zone zone, void f()) {
|
||||||
|
Expect.fail("Should not be called");
|
||||||
|
}));
|
||||||
|
|
||||||
|
nullFuture.then((value) {
|
||||||
|
Expect.isNull(value);
|
||||||
|
asyncEnd();
|
||||||
|
});
|
||||||
|
|
||||||
|
falseFuture.then((value) {
|
||||||
|
Expect.isFalse(value);
|
||||||
|
asyncEnd();
|
||||||
|
});
|
||||||
|
}();
|
||||||
|
}
|
Loading…
Reference in a new issue