Flow: typing of Scheduler (#25317)

Enables well formed exports for /scheduler. Some of the modules there were missing `@flow` and were therefore completely unchecked (despite some spurious types sprinkled around).
This commit is contained in:
Jan Kassens
2022-09-23 10:28:34 -04:00
committed by GitHub
parent cc8cb145f0
commit 135e33c954
9 changed files with 120 additions and 46 deletions
@@ -4,6 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
*/
export const enableSchedulerDebugging = false;
+8 -7
View File
@@ -7,23 +7,24 @@
* @flow strict
*/
type Heap = Array<Node>;
type Heap<T: Node> = Array<T>;
type Node = {
id: number,
sortIndex: number,
...
};
export function push(heap: Heap, node: Node): void {
export function push<T: Node>(heap: Heap<T>, node: T): void {
const index = heap.length;
heap.push(node);
siftUp(heap, node, index);
}
export function peek(heap: Heap): Node | null {
export function peek<T: Node>(heap: Heap<T>): T | null {
return heap.length === 0 ? null : heap[0];
}
export function pop(heap: Heap): Node | null {
export function pop<T: Node>(heap: Heap<T>): T | null {
if (heap.length === 0) {
return null;
}
@@ -36,7 +37,7 @@ export function pop(heap: Heap): Node | null {
return first;
}
function siftUp(heap, node, i) {
function siftUp<T: Node>(heap: Heap<T>, node: T, i: number): void {
let index = i;
while (index > 0) {
const parentIndex = (index - 1) >>> 1;
@@ -53,7 +54,7 @@ function siftUp(heap, node, i) {
}
}
function siftDown(heap, node, i) {
function siftDown<T: Node>(heap: Heap<T>, node: T, i: number): void {
let index = i;
const length = heap.length;
const halfLength = length >>> 1;
@@ -85,7 +86,7 @@ function siftDown(heap, node, i) {
}
}
function compare(a, b) {
function compare(a: Node, b: Node) {
// Compare sort index first, then task id.
const diff = a.sortIndex - b.sortIndex;
return diff !== 0 ? diff : a.id - b.id;
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @flow strict
*/
export type PriorityLevel = 0 | 1 | 2 | 3 | 4 | 5;
+53 -15
View File
@@ -4,10 +4,13 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/
/* eslint-disable no-var */
import type {PriorityLevel} from '../SchedulerPriorities';
import {
enableSchedulerDebugging,
enableProfiling,
@@ -41,7 +44,19 @@ import {
startLoggingProfilingEvents,
} from '../SchedulerProfiling';
let getCurrentTime;
export type Callback = boolean => ?Callback;
type Task = {
id: number,
callback: Callback | null,
priorityLevel: PriorityLevel,
startTime: number,
expirationTime: number,
sortIndex: number,
isQueued?: boolean,
};
let getCurrentTime: () => number | DOMHighResTimeStamp;
const hasPerformanceNow =
typeof performance === 'object' && typeof performance.now === 'function';
@@ -96,7 +111,9 @@ const localSetImmediate =
const isInputPending =
typeof navigator !== 'undefined' &&
// $FlowFixMe[prop-missing]
navigator.scheduling !== undefined &&
// $FlowFixMe[incompatible-type]
navigator.scheduling.isInputPending !== undefined
? navigator.scheduling.isInputPending.bind(navigator.scheduling)
: null;
@@ -247,7 +264,10 @@ function workLoop(hasTimeRemaining, initialTime) {
}
}
function unstable_runWithPriority(priorityLevel, eventHandler) {
function unstable_runWithPriority<T>(
priorityLevel: PriorityLevel,
eventHandler: () => T,
): T {
switch (priorityLevel) {
case ImmediatePriority:
case UserBlockingPriority:
@@ -269,7 +289,7 @@ function unstable_runWithPriority(priorityLevel, eventHandler) {
}
}
function unstable_next(eventHandler) {
function unstable_next<T>(eventHandler: () => T): T {
var priorityLevel;
switch (currentPriorityLevel) {
case ImmediatePriority:
@@ -294,8 +314,9 @@ function unstable_next(eventHandler) {
}
}
function unstable_wrapCallback(callback) {
function unstable_wrapCallback<T: (...Array<mixed>) => mixed>(callback: T): T {
var parentPriorityLevel = currentPriorityLevel;
// $FlowFixMe[incompatible-return]
return function() {
// This is a fork of runWithPriority, inlined for performance.
var previousPriorityLevel = currentPriorityLevel;
@@ -309,7 +330,11 @@ function unstable_wrapCallback(callback) {
};
}
function unstable_scheduleCallback(priorityLevel, callback, options) {
function unstable_scheduleCallback(
priorityLevel: PriorityLevel,
callback: Callback,
options?: {delay: number},
): Task {
var currentTime = getCurrentTime();
var startTime;
@@ -346,7 +371,7 @@ function unstable_scheduleCallback(priorityLevel, callback, options) {
var expirationTime = startTime + timeout;
var newTask = {
var newTask: Task = {
id: taskIdCounter++,
callback,
priorityLevel,
@@ -403,11 +428,11 @@ function unstable_continueExecution() {
}
}
function unstable_getFirstCallbackNode() {
function unstable_getFirstCallbackNode(): Task | null {
return peek(taskQueue);
}
function unstable_cancelCallback(task) {
function unstable_cancelCallback(task: Task) {
if (enableProfiling) {
if (task.isQueued) {
const currentTime = getCurrentTime();
@@ -422,13 +447,18 @@ function unstable_cancelCallback(task) {
task.callback = null;
}
function unstable_getCurrentPriorityLevel() {
function unstable_getCurrentPriorityLevel(): PriorityLevel {
return currentPriorityLevel;
}
let isMessageLoopRunning = false;
let scheduledHostCallback = null;
let taskTimeoutID = -1;
let scheduledHostCallback:
| null
| ((
hasTimeRemaining: boolean,
initialTime: DOMHighResTimeStamp | number,
) => boolean) = null;
let taskTimeoutID: TimeoutID = (-1: any);
// Scheduler periodically yields in case there is other work on the main
// thread, like user events. By default, it yields multiple times per frame.
@@ -441,7 +471,7 @@ let startTime = -1;
let needsPaint = false;
function shouldYieldToHost() {
function shouldYieldToHost(): boolean {
const timeElapsed = getCurrentTime() - startTime;
if (timeElapsed < frameInterval) {
// The main thread has only been blocked for a really short amount of time;
@@ -490,7 +520,9 @@ function requestPaint() {
if (
enableIsInputPending &&
navigator !== undefined &&
// $FlowFixMe[prop-missing]
navigator.scheduling !== undefined &&
// $FlowFixMe[incompatible-type]
navigator.scheduling.isInputPending !== undefined
) {
needsPaint = true;
@@ -499,7 +531,7 @@ function requestPaint() {
// Since we yield every frame regardless, `requestPaint` has no effect.
}
function forceFrameRate(fps) {
function forceFrameRate(fps: number) {
if (fps < 0 || fps > 125) {
// Using console['error'] to evade Babel and ESLint
console['error'](
@@ -579,6 +611,7 @@ if (typeof localSetImmediate === 'function') {
} else {
// We should only fallback here in non-browser environments.
schedulePerformWorkUntilDeadline = () => {
// $FlowFixMe[not-a-function] nullable value
localSetTimeout(performWorkUntilDeadline, 0);
};
}
@@ -592,14 +625,16 @@ function requestHostCallback(callback) {
}
function requestHostTimeout(callback, ms) {
// $FlowFixMe[not-a-function] nullable value
taskTimeoutID = localSetTimeout(() => {
callback(getCurrentTime());
}, ms);
}
function cancelHostTimeout() {
// $FlowFixMe[not-a-function] nullable value
localClearTimeout(taskTimeoutID);
taskTimeoutID = -1;
taskTimeoutID = ((-1: any): TimeoutID);
}
export {
@@ -623,7 +658,10 @@ export {
forceFrameRate as unstable_forceFrameRate,
};
export const unstable_Profiling = enableProfiling
export const unstable_Profiling: {
startLoggingProfilingEvents(): void,
stopLoggingProfilingEvents(): ArrayBuffer | null,
} | null = enableProfiling
? {
startLoggingProfilingEvents,
stopLoggingProfilingEvents,
@@ -3,7 +3,6 @@
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
// In www, these flags are controlled by GKs. Because most GKs have some
@@ -4,8 +4,10 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/
// $FlowFixMe[cannot-resolve-module]
const dynamicFeatureFlags = require('SchedulerFeatureFlags');
// Re-export dynamic flags from the www version.
@@ -19,4 +21,5 @@ export const {
maxYieldMs,
} = dynamicFeatureFlags;
export const enableProfiling = __PROFILE__ && enableProfilingFeatureFlag;
export const enableProfiling: boolean =
__PROFILE__ && enableProfilingFeatureFlag;
+49 -18
View File
@@ -4,11 +4,14 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/
/* eslint-disable no-var */
/* eslint-disable react-internal/prod-error-codes */
import type {PriorityLevel} from '../SchedulerPriorities';
import {
enableSchedulerDebugging,
enableProfiling,
@@ -36,6 +39,18 @@ import {
startLoggingProfilingEvents,
} from '../SchedulerProfiling';
type Callback = boolean => ?Callback;
type Task = {
id: number,
callback: Callback | null,
priorityLevel: PriorityLevel,
startTime: number,
expirationTime: number,
sortIndex: number,
isQueued?: boolean,
};
// Max 31 bit integer. The max integer size in V8 for 32-bit systems.
// Math.pow(2, 30) - 1
// 0b111111111111111111111111111111
@@ -52,7 +67,7 @@ var IDLE_PRIORITY_TIMEOUT = maxSigned31BitInt;
// Tasks are stored on a min heap
var taskQueue = [];
var timerQueue = [];
var timerQueue: Array<Task> = [];
// Incrementing id counter. Used to maintain insertion order.
var taskIdCounter = 1;
@@ -70,7 +85,12 @@ var isHostCallbackScheduled = false;
var isHostTimeoutScheduled = false;
let currentMockTime: number = 0;
let scheduledCallback: ((boolean, number) => void) | null = null;
let scheduledCallback:
| null
| ((
hasTimeRemaining: boolean,
initialTime: DOMHighResTimeStamp | number,
) => boolean) = null;
let scheduledTimeout: (number => void) | null = null;
let timeoutTime: number = -1;
let yieldedValues: Array<mixed> | null = null;
@@ -82,11 +102,11 @@ let shouldYieldForPaint: boolean = false;
var disableYieldValue = false;
function setDisableYieldValue(newValue) {
function setDisableYieldValue(newValue: boolean) {
disableYieldValue = newValue;
}
function advanceTimers(currentTime) {
function advanceTimers(currentTime: number) {
// Check for tasks that are no longer delayed and add them to the queue.
let timer = peek(timerQueue);
while (timer !== null) {
@@ -110,7 +130,7 @@ function advanceTimers(currentTime) {
}
}
function handleTimeout(currentTime) {
function handleTimeout(currentTime: number) {
isHostTimeoutScheduled = false;
advanceTimers(currentTime);
@@ -127,7 +147,7 @@ function handleTimeout(currentTime) {
}
}
function flushWork(hasTimeRemaining, initialTime) {
function flushWork(hasTimeRemaining: boolean, initialTime: number) {
if (enableProfiling) {
markSchedulerUnsuspended(initialTime);
}
@@ -169,7 +189,7 @@ function flushWork(hasTimeRemaining, initialTime) {
}
}
function workLoop(hasTimeRemaining, initialTime) {
function workLoop(hasTimeRemaining, initialTime: number): boolean {
let currentTime = initialTime;
advanceTimers(currentTime);
currentTask = peek(taskQueue);
@@ -238,7 +258,10 @@ function workLoop(hasTimeRemaining, initialTime) {
}
}
function unstable_runWithPriority(priorityLevel, eventHandler) {
function unstable_runWithPriority<T>(
priorityLevel: PriorityLevel,
eventHandler: () => T,
): T {
switch (priorityLevel) {
case ImmediatePriority:
case UserBlockingPriority:
@@ -260,7 +283,7 @@ function unstable_runWithPriority(priorityLevel, eventHandler) {
}
}
function unstable_next(eventHandler) {
function unstable_next<T>(eventHandler: () => T): T {
var priorityLevel;
switch (currentPriorityLevel) {
case ImmediatePriority:
@@ -285,8 +308,9 @@ function unstable_next(eventHandler) {
}
}
function unstable_wrapCallback(callback) {
function unstable_wrapCallback<T: (...Array<mixed>) => mixed>(callback: T): T {
var parentPriorityLevel = currentPriorityLevel;
// $FlowFixMe[incompatible-return]
return function() {
// This is a fork of runWithPriority, inlined for performance.
var previousPriorityLevel = currentPriorityLevel;
@@ -300,7 +324,11 @@ function unstable_wrapCallback(callback) {
};
}
function unstable_scheduleCallback(priorityLevel, callback, options) {
function unstable_scheduleCallback(
priorityLevel: PriorityLevel,
callback: Callback,
options?: {delay: number},
): Task {
var currentTime = getCurrentTime();
var startTime;
@@ -337,7 +365,7 @@ function unstable_scheduleCallback(priorityLevel, callback, options) {
var expirationTime = startTime + timeout;
var newTask = {
var newTask: Task = {
id: taskIdCounter++,
callback,
priorityLevel,
@@ -394,11 +422,11 @@ function unstable_continueExecution() {
}
}
function unstable_getFirstCallbackNode() {
function unstable_getFirstCallbackNode(): Task | null {
return peek(taskQueue);
}
function unstable_cancelCallback(task) {
function unstable_cancelCallback(task: Task) {
if (enableProfiling) {
if (task.isQueued) {
const currentTime = getCurrentTime();
@@ -413,11 +441,11 @@ function unstable_cancelCallback(task) {
task.callback = null;
}
function unstable_getCurrentPriorityLevel() {
function unstable_getCurrentPriorityLevel(): PriorityLevel {
return currentPriorityLevel;
}
function requestHostCallback(callback: boolean => void) {
function requestHostCallback(callback: (boolean, number) => boolean) {
scheduledCallback = callback;
}
@@ -494,7 +522,7 @@ function unstable_flushNumberOfYields(count: number): void {
}
}
function unstable_flushUntilNextPaint(): void {
function unstable_flushUntilNextPaint(): false {
if (isFlushing) {
throw new Error('Already flushing work.');
}
@@ -657,7 +685,10 @@ export {
setDisableYieldValue as unstable_setDisableYieldValue,
};
export const unstable_Profiling = enableProfiling
export const unstable_Profiling: {
startLoggingProfilingEvents(): void,
stopLoggingProfilingEvents(): ArrayBuffer | null,
} | null = enableProfiling
? {
startLoggingProfilingEvents,
stopLoggingProfilingEvents,
@@ -44,7 +44,7 @@ const setTimeout = window.setTimeout;
// Use experimental Chrome Scheduler postTask API.
const scheduler = global.scheduler;
const getCurrentTime = perf.now.bind(perf);
const getCurrentTime: () => DOMHighResTimeStamp = perf.now.bind(perf);
export const unstable_now = getCurrentTime;
@@ -193,7 +193,7 @@ export function unstable_runWithPriority<T>(
}
}
export function unstable_getCurrentPriorityLevel() {
export function unstable_getCurrentPriorityLevel(): PriorityLevel {
return currentPriorityLevel_DEPRECATED;
}
@@ -240,7 +240,7 @@ export function unstable_pauseExecution() {}
export function unstable_continueExecution() {}
export function unstable_getFirstCallbackNode() {
export function unstable_getFirstCallbackNode(): null {
return null;
}
+1
View File
@@ -51,6 +51,7 @@ well_formed_exports=true
well_formed_exports.includes=<PROJECT_ROOT>/packages/react-devtools-shared
well_formed_exports.includes=<PROJECT_ROOT>/packages/react-devtools-shell
well_formed_exports.includes=<PROJECT_ROOT>/packages/react-devtools-timeline
well_formed_exports.includes=<PROJECT_ROOT>/packages/scheduler
# Substituted by createFlowConfig.js:
%REACT_RENDERER_FLOW_OPTIONS%