Unverified Commit 9e658bc3 authored by Alexandre Ardhuin's avatar Alexandre Ardhuin Committed by GitHub

migrate scheduler to nullsafety (#61570)

parent fdf87edd
......@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
/// The Flutter Scheduler library.
///
/// To use, import `package:flutter/scheduler.dart`.
......
......@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'dart:async';
import 'dart:collection';
import 'dart:developer' show Flow, Timeline;
......@@ -57,7 +55,7 @@ typedef TaskCallback<T> = T Function();
/// See also:
///
/// * [defaultSchedulingStrategy], the default [SchedulingStrategy] for [SchedulerBinding.schedulingStrategy].
typedef SchedulingStrategy = bool Function({ int priority, SchedulerBinding scheduler });
typedef SchedulingStrategy = bool Function({ required int priority, required SchedulerBinding scheduler });
class _TaskEntry<T> {
_TaskEntry(this.task, this.priority, this.debugLabel, this.flow) {
......@@ -65,15 +63,14 @@ class _TaskEntry<T> {
debugStack = StackTrace.current;
return true;
}());
completer = Completer<T>();
}
final TaskCallback<T> task;
final int priority;
final String debugLabel;
final Flow flow;
final String? debugLabel;
final Flow? flow;
StackTrace debugStack;
Completer<T> completer;
late StackTrace debugStack;
final Completer<T> completer = Completer<T>();
void run() {
if (!kReleaseMode) {
......@@ -82,7 +79,7 @@ class _TaskEntry<T> {
() {
completer.complete(task());
},
flow: flow != null ? Flow.step(flow.id) : null,
flow: flow != null ? Flow.step(flow!.id) : null,
);
} else {
completer.complete(task());
......@@ -123,8 +120,8 @@ class _FrameCallbackEntry {
final FrameCallback callback;
static StackTrace debugCurrentCallbackStack;
StackTrace debugStack;
static StackTrace? debugCurrentCallbackStack;
StackTrace? debugStack;
}
/// The various phases that a [SchedulerBinding] goes through during
......@@ -292,7 +289,7 @@ mixin SchedulerBinding on BindingBase {
callback(timings);
}
} catch (exception, stack) {
InformationCollector collector;
InformationCollector? collector;
assert(() {
collector = () sync* {
yield DiagnosticsProperty<TimingsCallback>(
......@@ -314,8 +311,8 @@ mixin SchedulerBinding on BindingBase {
}
/// The current [SchedulerBinding], if one has been created.
static SchedulerBinding get instance => _instance;
static SchedulerBinding _instance;
static SchedulerBinding? get instance => _instance;
static SchedulerBinding? _instance;
@override
void initServiceExtensions() {
......@@ -340,8 +337,8 @@ mixin SchedulerBinding on BindingBase {
///
/// The preferred way to watch for changes to this value is using
/// [WidgetsBindingObserver.didChangeAppLifecycleState].
AppLifecycleState get lifecycleState => _lifecycleState;
AppLifecycleState _lifecycleState;
AppLifecycleState? get lifecycleState => _lifecycleState;
AppLifecycleState? _lifecycleState;
/// Called when the application lifecycle state changes.
///
......@@ -398,8 +395,8 @@ mixin SchedulerBinding on BindingBase {
Future<T> scheduleTask<T>(
TaskCallback<T> task,
Priority priority, {
String debugLabel,
Flow flow,
String? debugLabel,
Flow? flow,
}) {
final bool isFirstTask = _taskQueue.isEmpty;
final _TaskEntry<T> entry = _TaskEntry<T>(
......@@ -462,7 +459,7 @@ mixin SchedulerBinding on BindingBase {
_taskQueue.removeFirst();
entry.run();
} catch (exception, exceptionStack) {
StackTrace callbackStack;
StackTrace? callbackStack;
assert(() {
callbackStack = entry.debugStack;
return true;
......@@ -585,7 +582,7 @@ mixin SchedulerBinding on BindingBase {
);
}
for (final int id in callbacks.keys) {
final _FrameCallbackEntry entry = callbacks[id];
final _FrameCallbackEntry entry = callbacks[id]!;
yield DiagnosticsStackTrace('── callback $id ──', entry.debugStack, showSeparator: false);
}
},
......@@ -622,7 +619,7 @@ mixin SchedulerBinding on BindingBase {
debugPrint(
FlutterError.defaultStackFilter(
FlutterError.demangleStackTrace(
_FrameCallbackEntry.debugCurrentCallbackStack,
_FrameCallbackEntry.debugCurrentCallbackStack!,
).toString().trimRight().split('\n')
).join('\n')
);
......@@ -677,7 +674,7 @@ mixin SchedulerBinding on BindingBase {
_postFrameCallbacks.add(callback);
}
Completer<void> _nextFrameCompleter;
Completer<void>? _nextFrameCompleter;
/// Returns a Future that completes after the frame completes.
///
......@@ -694,11 +691,11 @@ mixin SchedulerBinding on BindingBase {
scheduleFrame();
_nextFrameCompleter = Completer<void>();
addPostFrameCallback((Duration timeStamp) {
_nextFrameCompleter.complete();
_nextFrameCompleter!.complete();
_nextFrameCompleter = null;
});
}
return _nextFrameCompleter.future;
return _nextFrameCompleter!.future;
}
/// Whether this scheduler has requested that [handleBeginFrame] be called soon.
......@@ -885,7 +882,7 @@ mixin SchedulerBinding on BindingBase {
});
}
Duration _firstRawTimeStampInEpoch;
Duration? _firstRawTimeStampInEpoch;
Duration _epochStart = Duration.zero;
Duration _lastRawTimeStamp = Duration.zero;
......@@ -920,7 +917,7 @@ mixin SchedulerBinding on BindingBase {
/// These mechanisms together combine to ensure that the durations we give
/// during frame callbacks are monotonically increasing.
Duration _adjustForEpoch(Duration rawTimeStamp) {
final Duration rawDurationSinceEpoch = _firstRawTimeStampInEpoch == null ? Duration.zero : rawTimeStamp - _firstRawTimeStampInEpoch;
final Duration rawDurationSinceEpoch = _firstRawTimeStampInEpoch == null ? Duration.zero : rawTimeStamp - _firstRawTimeStampInEpoch!;
return Duration(microseconds: (rawDurationSinceEpoch.inMicroseconds / timeDilation).round() + _epochStart.inMicroseconds);
}
......@@ -931,9 +928,9 @@ mixin SchedulerBinding on BindingBase {
/// produced.
Duration get currentFrameTimeStamp {
assert(_currentFrameTimeStamp != null);
return _currentFrameTimeStamp;
return _currentFrameTimeStamp!;
}
Duration _currentFrameTimeStamp;
Duration? _currentFrameTimeStamp;
/// The raw time stamp as provided by the engine to [Window.onBeginFrame]
/// for the frame currently being processed.
......@@ -952,7 +949,7 @@ mixin SchedulerBinding on BindingBase {
}
int _debugFrameNumber = 0;
String _debugBanner;
String? _debugBanner;
bool _ignoreNextEngineDrawFrame = false;
void _handleBeginFrame(Duration rawTimeStamp) {
......@@ -995,7 +992,7 @@ mixin SchedulerBinding on BindingBase {
/// [debugPrintEndFrameBanner] to true. This allows you to distinguish log
/// statements printed during a frame from those printed between frames (e.g.
/// in response to events or timers).
void handleBeginFrame(Duration rawTimeStamp) {
void handleBeginFrame(Duration? rawTimeStamp) {
Timeline.startSync('Frame', arguments: timelineArgumentsIndicatingLandmarkEvent);
_firstRawTimeStampInEpoch ??= rawTimeStamp;
_currentFrameTimeStamp = _adjustForEpoch(rawTimeStamp ?? _lastRawTimeStamp);
......@@ -1008,7 +1005,7 @@ mixin SchedulerBinding on BindingBase {
if (debugPrintBeginFrameBanner || debugPrintEndFrameBanner) {
final StringBuffer frameTimeStampDescription = StringBuffer();
if (rawTimeStamp != null) {
_debugDescribeTimeStamp(_currentFrameTimeStamp, frameTimeStampDescription);
_debugDescribeTimeStamp(_currentFrameTimeStamp!, frameTimeStampDescription);
} else {
frameTimeStampDescription.write('(warm-up frame)');
}
......@@ -1029,7 +1026,7 @@ mixin SchedulerBinding on BindingBase {
_transientCallbacks = <int, _FrameCallbackEntry>{};
callbacks.forEach((int id, _FrameCallbackEntry callbackEntry) {
if (!_removedIds.contains(id))
_invokeFrameCallback(callbackEntry.callback, _currentFrameTimeStamp, callbackEntry.debugStack);
_invokeFrameCallback(callbackEntry.callback, _currentFrameTimeStamp!, callbackEntry.debugStack);
});
_removedIds.clear();
} finally {
......@@ -1053,7 +1050,7 @@ mixin SchedulerBinding on BindingBase {
// PERSISTENT FRAME CALLBACKS
_schedulerPhase = SchedulerPhase.persistentCallbacks;
for (final FrameCallback callback in _persistentCallbacks)
_invokeFrameCallback(callback, _currentFrameTimeStamp);
_invokeFrameCallback(callback, _currentFrameTimeStamp!);
// POST-FRAME CALLBACKS
_schedulerPhase = SchedulerPhase.postFrameCallbacks;
......@@ -1061,13 +1058,13 @@ mixin SchedulerBinding on BindingBase {
List<FrameCallback>.from(_postFrameCallbacks);
_postFrameCallbacks.clear();
for (final FrameCallback callback in localPostFrameCallbacks)
_invokeFrameCallback(callback, _currentFrameTimeStamp);
_invokeFrameCallback(callback, _currentFrameTimeStamp!);
} finally {
_schedulerPhase = SchedulerPhase.idle;
Timeline.finishSync(); // end the Frame
assert(() {
if (debugPrintEndFrameBanner)
debugPrint('▀' * _debugBanner.length);
debugPrint('▀' * _debugBanner!.length);
_debugBanner = null;
return true;
}());
......@@ -1106,7 +1103,7 @@ mixin SchedulerBinding on BindingBase {
// Wraps the callback in a try/catch and forwards any error to
// [debugSchedulerExceptionHandler], if set. If not set, then simply prints
// the error.
void _invokeFrameCallback(FrameCallback callback, Duration timeStamp, [ StackTrace callbackStack ]) {
void _invokeFrameCallback(FrameCallback callback, Duration timeStamp, [ StackTrace? callbackStack ]) {
assert(callback != null);
assert(_FrameCallbackEntry.debugCurrentCallbackStack == null);
assert(() {
......@@ -1143,7 +1140,7 @@ mixin SchedulerBinding on BindingBase {
/// If there are any frame callbacks registered, only runs tasks with
/// a [Priority] of [Priority.animation] or higher. Otherwise, runs
/// all tasks.
bool defaultSchedulingStrategy({ int priority, SchedulerBinding scheduler }) {
bool defaultSchedulingStrategy({ required int priority, required SchedulerBinding scheduler }) {
if (scheduler.transientCallbackCount > 0)
return priority >= Priority.animation.value;
return true;
......
......@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'package:flutter/foundation.dart';
// Any changes to this file should be reflected in the debugAssertAllSchedulerVarsUnset()
......
......@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'package:flutter/foundation.dart';
/// A task priority, as passed to [SchedulerBinding.scheduleTask].
......
......@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'dart:async';
import 'package:flutter/foundation.dart';
......@@ -71,7 +69,7 @@ class Ticker {
}());
}
TickerFuture _future;
TickerFuture? _future;
/// Whether this ticker has been silenced.
///
......@@ -115,9 +113,9 @@ class Ticker {
return false;
if (muted)
return false;
if (SchedulerBinding.instance.framesEnabled)
if (SchedulerBinding.instance!.framesEnabled)
return true;
if (SchedulerBinding.instance.schedulerPhase != SchedulerPhase.idle)
if (SchedulerBinding.instance!.schedulerPhase != SchedulerPhase.idle)
return true; // for example, we might be in a warm-up frame or forced frame
return false;
}
......@@ -130,7 +128,7 @@ class Ticker {
/// [isTicking].
bool get isActive => _future != null;
Duration _startTime;
Duration? _startTime;
/// Starts the clock for this [Ticker]. If the ticker is not [muted], then this
/// also starts calling the ticker's callback once per animation frame.
......@@ -163,10 +161,10 @@ class Ticker {
if (shouldScheduleTick) {
scheduleTick();
}
if (SchedulerBinding.instance.schedulerPhase.index > SchedulerPhase.idle.index &&
SchedulerBinding.instance.schedulerPhase.index < SchedulerPhase.postFrameCallbacks.index)
_startTime = SchedulerBinding.instance.currentFrameTimeStamp;
return _future;
if (SchedulerBinding.instance!.schedulerPhase.index > SchedulerPhase.idle.index &&
SchedulerBinding.instance!.schedulerPhase.index < SchedulerPhase.postFrameCallbacks.index)
_startTime = SchedulerBinding.instance!.currentFrameTimeStamp;
return _future!;
}
/// Adds a debug representation of a [Ticker] optimized for including in error
......@@ -197,7 +195,7 @@ class Ticker {
// We take the _future into a local variable so that isTicking is false
// when we actually complete the future (isTicking uses _future to
// determine its state).
final TickerFuture localFuture = _future;
final TickerFuture localFuture = _future!;
_future = null;
_startTime = null;
assert(!isActive);
......@@ -213,7 +211,7 @@ class Ticker {
final TickerCallback _onTick;
int _animationId;
int? _animationId;
/// Whether this [Ticker] has already scheduled a frame callback.
@protected
......@@ -237,7 +235,7 @@ class Ticker {
_animationId = null;
_startTime ??= timeStamp;
_onTick(timeStamp - _startTime);
_onTick(timeStamp - _startTime!);
// The onTick callback may have scheduled another tick already, for
// example by calling stop then start again.
......@@ -252,7 +250,7 @@ class Ticker {
void scheduleTick({ bool rescheduling = false }) {
assert(!scheduled);
assert(shouldScheduleTick);
_animationId = SchedulerBinding.instance.scheduleFrameCallback(_tick, rescheduling: rescheduling);
_animationId = SchedulerBinding.instance!.scheduleFrameCallback(_tick, rescheduling: rescheduling);
}
/// Cancels the frame callback that was requested by [scheduleTick], if any.
......@@ -264,7 +262,7 @@ class Ticker {
@protected
void unscheduleTick() {
if (scheduled) {
SchedulerBinding.instance.cancelFrameCallbackWithId(_animationId);
SchedulerBinding.instance!.cancelFrameCallbackWithId(_animationId!);
_animationId = null;
}
assert(!shouldScheduleTick);
......@@ -301,7 +299,7 @@ class Ticker {
@mustCallSuper
void dispose() {
if (_future != null) {
final TickerFuture localFuture = _future;
final TickerFuture localFuture = _future!;
_future = null;
assert(!isActive);
unscheduleTick();
......@@ -319,8 +317,8 @@ class Ticker {
/// An optional label can be provided for debugging purposes.
///
/// This label will appear in the [toString] output in debug builds.
final String debugLabel;
StackTrace _debugCreationStack;
final String? debugLabel;
late StackTrace _debugCreationStack;
@override
String toString({ bool debugIncludeStack = false }) {
......@@ -374,14 +372,14 @@ class TickerFuture implements Future<void> {
}
final Completer<void> _primaryCompleter = Completer<void>();
Completer<void> _secondaryCompleter;
bool _completed; // null means unresolved, true means complete, false means canceled
Completer<void>? _secondaryCompleter;
bool? _completed; // null means unresolved, true means complete, false means canceled
void _complete() {
assert(_completed == null);
_completed = true;
_primaryCompleter.complete(null);
_secondaryCompleter?.complete(null);
_primaryCompleter.complete();
_secondaryCompleter?.complete();
}
void _cancel(Ticker ticker) {
......@@ -415,14 +413,14 @@ class TickerFuture implements Future<void> {
if (_secondaryCompleter == null) {
_secondaryCompleter = Completer<void>();
if (_completed != null) {
if (_completed) {
_secondaryCompleter.complete();
if (_completed!) {
_secondaryCompleter!.complete();
} else {
_secondaryCompleter.completeError(const TickerCanceled());
_secondaryCompleter!.completeError(const TickerCanceled());
}
}
}
return _secondaryCompleter.future;
return _secondaryCompleter!.future;
}
@override
......@@ -431,17 +429,17 @@ class TickerFuture implements Future<void> {
}
@override
Future<void> catchError(Function onError, { bool test(dynamic error) }) {
Future<void> catchError(Function onError, { bool Function(Object)? test }) {
return _primaryCompleter.future.catchError(onError, test: test);
}
@override
Future<R> then<R>(FutureOr<R> onValue(void value), { Function onError }) {
Future<R> then<R>(FutureOr<R> onValue(void value), { Function? onError }) {
return _primaryCompleter.future.then<R>(onValue, onError: onError);
}
@override
Future<void> timeout(Duration timeLimit, { dynamic onTimeout() }) {
Future<void> timeout(Duration timeLimit, { FutureOr<void> Function()? onTimeout }) {
return _primaryCompleter.future.timeout(timeLimit, onTimeout: onTimeout);
}
......@@ -451,7 +449,7 @@ class TickerFuture implements Future<void> {
}
@override
String toString() => '${describeIdentity(this)}(${ _completed == null ? "active" : _completed ? "complete" : "canceled" })';
String toString() => '${describeIdentity(this)}(${ _completed == null ? "active" : _completed! ? "complete" : "canceled" })';
}
/// Exception thrown by [Ticker] objects on the [TickerFuture.orCancel] future
......@@ -464,7 +462,7 @@ class TickerCanceled implements Exception {
///
/// This may be null in the case that the [Future] created for
/// [TickerFuture.orCancel] was created after the ticker was canceled.
final Ticker ticker;
final Ticker? ticker;
@override
String toString() {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment