@samitouri / QOS-React-2 / commits / 88ef95712d

Fork ReactFiberLane (#20371)

This wasn't forked previously because Lane and associated types are opaque, and they leak into non-reconciler packages. So forking the type would also require forking all those other packages. But I really want to use the reconciler fork infra for lanes changes. So I made them no longer opaque. Another possible solution would be to add separate `new` and `old` fields to the Fiber type, like I did when migrating from expiration times. But that seems so excessive. This seems fine. But we should still treat them like they're opaque and only do lanes manipulation in the ReactFiberLane module. At least until the model stabilizes more. We'll just need to enforce this with discipline instead of with the type system.

Andrew Clark committed Dec 4, 2020 at 10:54 UTC 88ef95712d315705b2d6654f3c0d5c5ace4a6456
44 files changed +944 -69
packages/react-dom/src/events/ReactDOMEventListener.js
+21 -4
@@ -41,6 +41,7 @@ import {getClosestInstanceFromNode} from '../client/ReactDOMComponentTree';
41 import {
42 enableLegacyFBSupport,
43 decoupleUpdatePriorityFromScheduler,
44 + enableNewReconciler,
45 } from 'shared/ReactFeatureFlags';
46 import {
47 UserBlockingEvent,
@@ -53,11 +54,27 @@ import {
54 flushDiscreteUpdatesIfNeeded,
55 discreteUpdates,
56 } from './ReactDOMUpdateBatching';
57 +
58 +import {
59 + InputContinuousLanePriority as InputContinuousLanePriority_old,
60 + getCurrentUpdateLanePriority as getCurrentUpdateLanePriority_old,
61 + setCurrentUpdateLanePriority as setCurrentUpdateLanePriority_old,
62 +} from 'react-reconciler/src/ReactFiberLane.old';
63 import {
57 - InputContinuousLanePriority,
58 - getCurrentUpdateLanePriority,
59 - setCurrentUpdateLanePriority,
60 -} from 'react-reconciler/src/ReactFiberLane';
64 + InputContinuousLanePriority as InputContinuousLanePriority_new,
65 + getCurrentUpdateLanePriority as getCurrentUpdateLanePriority_new,
66 + setCurrentUpdateLanePriority as setCurrentUpdateLanePriority_new,
67 +} from 'react-reconciler/src/ReactFiberLane.new';
68 +
69 +const InputContinuousLanePriority = enableNewReconciler
70 + ? InputContinuousLanePriority_new
71 + : InputContinuousLanePriority_old;
72 +const getCurrentUpdateLanePriority = enableNewReconciler
73 + ? getCurrentUpdateLanePriority_new
74 + : getCurrentUpdateLanePriority_old;
75 +const setCurrentUpdateLanePriority = enableNewReconciler
76 + ? setCurrentUpdateLanePriority_new
77 + : setCurrentUpdateLanePriority_old;
78
79 const {
80 unstable_UserBlockingPriority: UserBlockingPriority,
packages/react-dom/src/events/ReactDOMEventReplaying.js
+1 -1
@@ -12,7 +12,7 @@ import type {Container, SuspenseInstance} from '../client/ReactDOMHostConfig';
12 import type {DOMEventName} from '../events/DOMEventNames';
13 import type {EventSystemFlags} from './EventSystemFlags';
14 import type {FiberRoot} from 'react-reconciler/src/ReactInternalTypes';
15 -import type {LanePriority} from 'react-reconciler/src/ReactFiberLane';
15 +import type {LanePriority} from 'react-reconciler/src/ReactFiberLane.old';
16
17 import {enableSelectiveHydration} from 'shared/ReactFeatureFlags';
18 import {
packages/react-reconciler/src/DebugTracing.js
+1 -1
@@ -7,7 +7,7 @@
7 * @flow
8 */
9
10 -import type {Lane, Lanes} from './ReactFiberLane';
10 +import type {Lane, Lanes} from './ReactFiberLane.old';
11 import type {Wakeable} from 'shared/ReactTypes';
12
13 import {enableDebugTracing} from 'shared/ReactFeatureFlags';
packages/react-reconciler/src/ReactChildFiber.new.js
+1 -1
@@ -10,7 +10,7 @@
10 import type {ReactElement} from 'shared/ReactElementType';
11 import type {ReactPortal} from 'shared/ReactTypes';
12 import type {Fiber} from './ReactInternalTypes';
13 -import type {Lanes} from './ReactFiberLane';
13 +import type {Lanes} from './ReactFiberLane.new';
14
15 import getComponentName from 'shared/getComponentName';
16 import {Placement, Deletion} from './ReactFiberFlags';
packages/react-reconciler/src/ReactChildFiber.old.js
+1 -1
@@ -10,7 +10,7 @@
10 import type {ReactElement} from 'shared/ReactElementType';
11 import type {ReactPortal} from 'shared/ReactTypes';
12 import type {Fiber} from './ReactInternalTypes';
13 -import type {Lanes} from './ReactFiberLane';
13 +import type {Lanes} from './ReactFiberLane.old';
14
15 import getComponentName from 'shared/getComponentName';
16 import {Placement, Deletion} from './ReactFiberFlags';
packages/react-reconciler/src/ReactFiber.new.js
+2 -2
@@ -18,7 +18,7 @@ import type {Fiber} from './ReactInternalTypes';
18 import type {RootTag} from './ReactRootTags';
19 import type {WorkTag} from './ReactWorkTags';
20 import type {TypeOfMode} from './ReactTypeOfMode';
21 -import type {Lanes} from './ReactFiberLane';
21 +import type {Lanes} from './ReactFiberLane.new';
22 import type {SuspenseInstance} from './ReactFiberHostConfig';
23 import type {OffscreenProps} from './ReactFiberOffscreenComponent';
24
@@ -63,7 +63,7 @@ import {
63 resolveFunctionForHotReloading,
64 resolveForwardRefForHotReloading,
65 } from './ReactFiberHotReloading.new';
66 -import {NoLanes} from './ReactFiberLane';
66 +import {NoLanes} from './ReactFiberLane.new';
67 import {
68 NoMode,
69 ConcurrentMode,
packages/react-reconciler/src/ReactFiber.old.js
+2 -2
@@ -18,7 +18,7 @@ import type {Fiber} from './ReactInternalTypes';
18 import type {RootTag} from './ReactRootTags';
19 import type {WorkTag} from './ReactWorkTags';
20 import type {TypeOfMode} from './ReactTypeOfMode';
21 -import type {Lanes} from './ReactFiberLane';
21 +import type {Lanes} from './ReactFiberLane.old';
22 import type {SuspenseInstance} from './ReactFiberHostConfig';
23 import type {OffscreenProps} from './ReactFiberOffscreenComponent';
24
@@ -63,7 +63,7 @@ import {
63 resolveFunctionForHotReloading,
64 resolveForwardRefForHotReloading,
65 } from './ReactFiberHotReloading.old';
66 -import {NoLanes} from './ReactFiberLane';
66 +import {NoLanes} from './ReactFiberLane.old';
67 import {
68 NoMode,
69 ConcurrentMode,
packages/react-reconciler/src/ReactFiberBeginWork.new.js
+2 -2
@@ -11,7 +11,7 @@ import type {ReactProviderType, ReactContext} from 'shared/ReactTypes';
11 import type {LazyComponent as LazyComponentType} from 'react/src/ReactLazy';
12 import type {Fiber} from './ReactInternalTypes';
13 import type {FiberRoot} from './ReactInternalTypes';
14 -import type {Lanes, Lane} from './ReactFiberLane';
14 +import type {Lanes, Lane} from './ReactFiberLane.new';
15 import type {MutableSource} from 'shared/ReactTypes';
16 import type {
17 SuspenseState,
@@ -113,7 +113,7 @@ import {
113 removeLanes,
114 mergeLanes,
115 getBumpedLaneForHydration,
116 -} from './ReactFiberLane';
116 +} from './ReactFiberLane.new';
117 import {
118 ConcurrentMode,
119 NoMode,
packages/react-reconciler/src/ReactFiberBeginWork.old.js
+2 -2
@@ -11,7 +11,7 @@ import type {ReactProviderType, ReactContext} from 'shared/ReactTypes';
11 import type {LazyComponent as LazyComponentType} from 'react/src/ReactLazy';
12 import type {Fiber} from './ReactInternalTypes';
13 import type {FiberRoot} from './ReactInternalTypes';
14 -import type {Lanes, Lane} from './ReactFiberLane';
14 +import type {Lanes, Lane} from './ReactFiberLane.old';
15 import type {MutableSource} from 'shared/ReactTypes';
16 import type {
17 SuspenseState,
@@ -113,7 +113,7 @@ import {
113 removeLanes,
114 mergeLanes,
115 getBumpedLaneForHydration,
116 -} from './ReactFiberLane';
116 +} from './ReactFiberLane.old';
117 import {
118 ConcurrentMode,
119 NoMode,
packages/react-reconciler/src/ReactFiberClassComponent.new.js
+2 -2
@@ -8,7 +8,7 @@
8 */
9
10 import type {Fiber} from './ReactInternalTypes';
11 -import type {Lanes} from './ReactFiberLane';
11 +import type {Lanes} from './ReactFiberLane.new';
12 import type {UpdateQueue} from './ReactUpdateQueue.new';
13
14 import * as React from 'react';
@@ -42,7 +42,7 @@ import {
42 initializeUpdateQueue,
43 cloneUpdateQueue,
44 } from './ReactUpdateQueue.new';
45 -import {NoLanes} from './ReactFiberLane';
45 +import {NoLanes} from './ReactFiberLane.new';
46 import {
47 cacheContext,
48 getMaskedContext,
packages/react-reconciler/src/ReactFiberClassComponent.old.js
+2 -2
@@ -8,7 +8,7 @@
8 */
9
10 import type {Fiber} from './ReactInternalTypes';
11 -import type {Lanes} from './ReactFiberLane';
11 +import type {Lanes} from './ReactFiberLane.old';
12 import type {UpdateQueue} from './ReactUpdateQueue.old';
13
14 import * as React from 'react';
@@ -42,7 +42,7 @@ import {
42 initializeUpdateQueue,
43 cloneUpdateQueue,
44 } from './ReactUpdateQueue.old';
45 -import {NoLanes} from './ReactFiberLane';
45 +import {NoLanes} from './ReactFiberLane.old';
46 import {
47 cacheContext,
48 getMaskedContext,
packages/react-reconciler/src/ReactFiberCommitWork.new.js
+1 -1
@@ -17,7 +17,7 @@ import type {
17 } from './ReactFiberHostConfig';
18 import type {Fiber} from './ReactInternalTypes';
19 import type {FiberRoot} from './ReactInternalTypes';
20 -import type {Lanes} from './ReactFiberLane';
20 +import type {Lanes} from './ReactFiberLane.new';
21 import type {SuspenseState} from './ReactFiberSuspenseComponent.new';
22 import type {UpdateQueue} from './ReactUpdateQueue.new';
23 import type {FunctionComponentUpdateQueue} from './ReactFiberHooks.new';
packages/react-reconciler/src/ReactFiberCommitWork.old.js
+1 -1
@@ -17,7 +17,7 @@ import type {
17 } from './ReactFiberHostConfig';
18 import type {Fiber} from './ReactInternalTypes';
19 import type {FiberRoot} from './ReactInternalTypes';
20 -import type {Lanes} from './ReactFiberLane';
20 +import type {Lanes} from './ReactFiberLane.old';
21 import type {SuspenseState} from './ReactFiberSuspenseComponent.old';
22 import type {UpdateQueue} from './ReactUpdateQueue.old';
23 import type {FunctionComponentUpdateQueue} from './ReactFiberHooks.old';
packages/react-reconciler/src/ReactFiberCompleteWork.new.js
+2 -2
@@ -8,7 +8,7 @@
8 */
9
10 import type {Fiber} from './ReactInternalTypes';
11 -import type {Lanes} from './ReactFiberLane';
11 +import type {Lanes} from './ReactFiberLane.new';
12 import type {
13 ReactFundamentalComponentInstance,
14 ReactScopeInstance,
@@ -130,7 +130,7 @@ import {
130 getRenderTargetTime,
131 } from './ReactFiberWorkLoop.new';
132 import {createFundamentalStateInstance} from './ReactFiberFundamental.new';
133 -import {OffscreenLane, SomeRetryLane} from './ReactFiberLane';
133 +import {OffscreenLane, SomeRetryLane} from './ReactFiberLane.new';
134 import {resetChildFibers} from './ReactChildFiber.new';
135 import {createScopeInstance} from './ReactFiberScope.new';
136 import {transferActualDuration} from './ReactProfilerTimer.new';
packages/react-reconciler/src/ReactFiberCompleteWork.old.js
+2 -2
@@ -8,7 +8,7 @@
8 */
9
10 import type {Fiber} from './ReactInternalTypes';
11 -import type {Lanes} from './ReactFiberLane';
11 +import type {Lanes} from './ReactFiberLane.old';
12 import type {
13 ReactFundamentalComponentInstance,
14 ReactScopeInstance,
@@ -130,7 +130,7 @@ import {
130 getRenderTargetTime,
131 } from './ReactFiberWorkLoop.old';
132 import {createFundamentalStateInstance} from './ReactFiberFundamental.old';
133 -import {OffscreenLane, SomeRetryLane} from './ReactFiberLane';
133 +import {OffscreenLane, SomeRetryLane} from './ReactFiberLane.old';
134 import {resetChildFibers} from './ReactChildFiber.old';
135 import {createScopeInstance} from './ReactFiberScope.old';
136 import {transferActualDuration} from './ReactProfilerTimer.old';
packages/react-reconciler/src/ReactFiberHooks.new.js
+2 -2
@@ -14,7 +14,7 @@ import type {
14 ReactContext,
15 } from 'shared/ReactTypes';
16 import type {Fiber, Dispatcher, HookType} from './ReactInternalTypes';
17 -import type {Lanes, Lane} from './ReactFiberLane';
17 +import type {Lanes, Lane} from './ReactFiberLane.new';
18 import type {HookFlags} from './ReactHookEffectTags';
19 import type {ReactPriorityLevel} from './ReactInternalTypes';
20 import type {FiberRoot} from './ReactInternalTypes';
@@ -44,7 +44,7 @@ import {
44 setCurrentUpdateLanePriority,
45 higherLanePriority,
46 DefaultLanePriority,
47 -} from './ReactFiberLane';
47 +} from './ReactFiberLane.new';
48 import {readContext} from './ReactFiberNewContext.new';
49 import {
50 Update as UpdateEffect,
packages/react-reconciler/src/ReactFiberHooks.old.js
+2 -2
@@ -14,7 +14,7 @@ import type {
14 ReactContext,
15 } from 'shared/ReactTypes';
16 import type {Fiber, Dispatcher, HookType} from './ReactInternalTypes';
17 -import type {Lanes, Lane} from './ReactFiberLane';
17 +import type {Lanes, Lane} from './ReactFiberLane.old';
18 import type {HookFlags} from './ReactHookEffectTags';
19 import type {ReactPriorityLevel} from './ReactInternalTypes';
20 import type {FiberRoot} from './ReactInternalTypes';
@@ -44,7 +44,7 @@ import {
44 setCurrentUpdateLanePriority,
45 higherLanePriority,
46 DefaultLanePriority,
47 -} from './ReactFiberLane';
47 +} from './ReactFiberLane.old';
48 import {readContext} from './ReactFiberNewContext.old';
49 import {
50 Update as UpdateEffect,
packages/react-reconciler/src/ReactFiberHotReloading.new.js
+1 -1
@@ -20,7 +20,7 @@ import {
20 } from './ReactFiberWorkLoop.new';
21 import {updateContainer} from './ReactFiberReconciler.new';
22 import {emptyContextObject} from './ReactFiberContext.new';
23 -import {SyncLane, NoTimestamp} from './ReactFiberLane';
23 +import {SyncLane, NoTimestamp} from './ReactFiberLane.new';
24 import {
25 ClassComponent,
26 FunctionComponent,
packages/react-reconciler/src/ReactFiberHotReloading.old.js
+1 -1
@@ -20,7 +20,7 @@ import {
20 } from './ReactFiberWorkLoop.old';
21 import {updateContainer} from './ReactFiberReconciler.old';
22 import {emptyContextObject} from './ReactFiberContext.old';
23 -import {SyncLane, NoTimestamp} from './ReactFiberLane';
23 +import {SyncLane, NoTimestamp} from './ReactFiberLane.old';
24 import {
25 ClassComponent,
26 FunctionComponent,
packages/react-reconciler/src/ReactFiberHydrationContext.new.js
+1 -1
@@ -55,7 +55,7 @@ import {
55 didNotFindHydratableSuspenseInstance,
56 } from './ReactFiberHostConfig';
57 import {enableSuspenseServerRenderer} from 'shared/ReactFeatureFlags';
58 -import {OffscreenLane} from './ReactFiberLane';
58 +import {OffscreenLane} from './ReactFiberLane.new';
59
60 // The deepest Fiber on the stack involved in a hydration context.
61 // This may have been an insertion or a hydration.
packages/react-reconciler/src/ReactFiberHydrationContext.old.js
+1 -1
@@ -55,7 +55,7 @@ import {
55 didNotFindHydratableSuspenseInstance,
56 } from './ReactFiberHostConfig';
57 import {enableSuspenseServerRenderer} from 'shared/ReactFeatureFlags';
58 -import {OffscreenLane} from './ReactFiberLane';
58 +import {OffscreenLane} from './ReactFiberLane.old';
59
60 // The deepest Fiber on the stack involved in a hydration context.
61 // This may have been an insertion or a hydration.
packages/react-reconciler/src/ReactFiberLane.new.js renamed
+7 -4
@@ -9,7 +9,9 @@
9
10 import type {FiberRoot, ReactPriorityLevel} from './ReactInternalTypes';
11
12 -export opaque type LanePriority =
12 +// TODO: Ideally these types would be opaque but that doesn't work well with
13 +// our reconciler fork infra, since these leak into non-reconciler packages.
14 +export type LanePriority =
15 | 0
16 | 1
17 | 2
@@ -28,9 +30,10 @@ export opaque type LanePriority =
30 | 15
31 | 16
32 | 17;
31 -export opaque type Lanes = number;
32 -export opaque type Lane = number;
33 -export opaque type LaneMap<T> = Array<T>;
33 +
34 +export type Lanes = number;
35 +export type Lane = number;
36 +export type LaneMap<T> = Array<T>;
37
38 import invariant from 'shared/invariant';
39
packages/react-reconciler/src/ReactFiberLane.old.js new
+845
@@ -0,0 +1,845 @@
1 +/**
2 + * Copyright (c) Facebook, Inc. and its affiliates.
3 + *
4 + * This source code is licensed under the MIT license found in the
5 + * LICENSE file in the root directory of this source tree.
6 + *
7 + * @flow
8 + */
9 +
10 +import type {FiberRoot, ReactPriorityLevel} from './ReactInternalTypes';
11 +
12 +// TODO: Ideally these types would be opaque but that doesn't work well with
13 +// our reconciler fork infra, since these leak into non-reconciler packages.
14 +export type LanePriority =
15 + | 0
16 + | 1
17 + | 2
18 + | 3
19 + | 4
20 + | 5
21 + | 6
22 + | 7
23 + | 8
24 + | 9
25 + | 10
26 + | 11
27 + | 12
28 + | 13
29 + | 14
30 + | 15
31 + | 16
32 + | 17;
33 +
34 +export type Lanes = number;
35 +export type Lane = number;
36 +export type LaneMap<T> = Array<T>;
37 +
38 +import invariant from 'shared/invariant';
39 +
40 +import {
41 + ImmediatePriority as ImmediateSchedulerPriority,
42 + UserBlockingPriority as UserBlockingSchedulerPriority,
43 + NormalPriority as NormalSchedulerPriority,
44 + LowPriority as LowSchedulerPriority,
45 + IdlePriority as IdleSchedulerPriority,
46 + NoPriority as NoSchedulerPriority,
47 +} from './SchedulerWithReactIntegration.old';
48 +
49 +export const SyncLanePriority: LanePriority = 15;
50 +export const SyncBatchedLanePriority: LanePriority = 14;
51 +
52 +const InputDiscreteHydrationLanePriority: LanePriority = 13;
53 +export const InputDiscreteLanePriority: LanePriority = 12;
54 +
55 +const InputContinuousHydrationLanePriority: LanePriority = 11;
56 +export const InputContinuousLanePriority: LanePriority = 10;
57 +
58 +const DefaultHydrationLanePriority: LanePriority = 9;
59 +export const DefaultLanePriority: LanePriority = 8;
60 +
61 +const TransitionHydrationPriority: LanePriority = 7;
62 +export const TransitionPriority: LanePriority = 6;
63 +
64 +const RetryLanePriority: LanePriority = 5;
65 +
66 +const SelectiveHydrationLanePriority: LanePriority = 4;
67 +
68 +const IdleHydrationLanePriority: LanePriority = 3;
69 +const IdleLanePriority: LanePriority = 2;
70 +
71 +const OffscreenLanePriority: LanePriority = 1;
72 +
73 +export const NoLanePriority: LanePriority = 0;
74 +
75 +const TotalLanes = 31;
76 +
77 +export const NoLanes: Lanes = /* */ 0b0000000000000000000000000000000;
78 +export const NoLane: Lane = /* */ 0b0000000000000000000000000000000;
79 +
80 +export const SyncLane: Lane = /* */ 0b0000000000000000000000000000001;
81 +export const SyncBatchedLane: Lane = /* */ 0b0000000000000000000000000000010;
82 +
83 +export const InputDiscreteHydrationLane: Lane = /* */ 0b0000000000000000000000000000100;
84 +const InputDiscreteLanes: Lanes = /* */ 0b0000000000000000000000000011000;
85 +
86 +const InputContinuousHydrationLane: Lane = /* */ 0b0000000000000000000000000100000;
87 +const InputContinuousLanes: Lanes = /* */ 0b0000000000000000000000011000000;
88 +
89 +export const DefaultHydrationLane: Lane = /* */ 0b0000000000000000000000100000000;
90 +export const DefaultLanes: Lanes = /* */ 0b0000000000000000000111000000000;
91 +
92 +const TransitionHydrationLane: Lane = /* */ 0b0000000000000000001000000000000;
93 +const TransitionLanes: Lanes = /* */ 0b0000000001111111110000000000000;
94 +
95 +const RetryLanes: Lanes = /* */ 0b0000011110000000000000000000000;
96 +
97 +export const SomeRetryLane: Lanes = /* */ 0b0000010000000000000000000000000;
98 +
99 +export const SelectiveHydrationLane: Lane = /* */ 0b0000100000000000000000000000000;
100 +
101 +const NonIdleLanes = /* */ 0b0000111111111111111111111111111;
102 +
103 +export const IdleHydrationLane: Lane = /* */ 0b0001000000000000000000000000000;
104 +const IdleLanes: Lanes = /* */ 0b0110000000000000000000000000000;
105 +
106 +export const OffscreenLane: Lane = /* */ 0b1000000000000000000000000000000;
107 +
108 +export const NoTimestamp = -1;
109 +
110 +let currentUpdateLanePriority: LanePriority = NoLanePriority;
111 +
112 +export function getCurrentUpdateLanePriority(): LanePriority {
113 + return currentUpdateLanePriority;
114 +}
115 +
116 +export function setCurrentUpdateLanePriority(newLanePriority: LanePriority) {
117 + currentUpdateLanePriority = newLanePriority;
118 +}
119 +
120 +// "Registers" used to "return" multiple values
121 +// Used by getHighestPriorityLanes and getNextLanes:
122 +let return_highestLanePriority: LanePriority = DefaultLanePriority;
123 +
124 +function getHighestPriorityLanes(lanes: Lanes | Lane): Lanes {
125 + if ((SyncLane & lanes) !== NoLanes) {
126 + return_highestLanePriority = SyncLanePriority;
127 + return SyncLane;
128 + }
129 + if ((SyncBatchedLane & lanes) !== NoLanes) {
130 + return_highestLanePriority = SyncBatchedLanePriority;
131 + return SyncBatchedLane;
132 + }
133 + if ((InputDiscreteHydrationLane & lanes) !== NoLanes) {
134 + return_highestLanePriority = InputDiscreteHydrationLanePriority;
135 + return InputDiscreteHydrationLane;
136 + }
137 + const inputDiscreteLanes = InputDiscreteLanes & lanes;
138 + if (inputDiscreteLanes !== NoLanes) {
139 + return_highestLanePriority = InputDiscreteLanePriority;
140 + return inputDiscreteLanes;
141 + }
142 + if ((lanes & InputContinuousHydrationLane) !== NoLanes) {
143 + return_highestLanePriority = InputContinuousHydrationLanePriority;
144 + return InputContinuousHydrationLane;
145 + }
146 + const inputContinuousLanes = InputContinuousLanes & lanes;
147 + if (inputContinuousLanes !== NoLanes) {
148 + return_highestLanePriority = InputContinuousLanePriority;
149 + return inputContinuousLanes;
150 + }
151 + if ((lanes & DefaultHydrationLane) !== NoLanes) {
152 + return_highestLanePriority = DefaultHydrationLanePriority;
153 + return DefaultHydrationLane;
154 + }
155 + const defaultLanes = DefaultLanes & lanes;
156 + if (defaultLanes !== NoLanes) {
157 + return_highestLanePriority = DefaultLanePriority;
158 + return defaultLanes;
159 + }
160 + if ((lanes & TransitionHydrationLane) !== NoLanes) {
161 + return_highestLanePriority = TransitionHydrationPriority;
162 + return TransitionHydrationLane;
163 + }
164 + const transitionLanes = TransitionLanes & lanes;
165 + if (transitionLanes !== NoLanes) {
166 + return_highestLanePriority = TransitionPriority;
167 + return transitionLanes;
168 + }
169 + const retryLanes = RetryLanes & lanes;
170 + if (retryLanes !== NoLanes) {
171 + return_highestLanePriority = RetryLanePriority;
172 + return retryLanes;
173 + }
174 + if (lanes & SelectiveHydrationLane) {
175 + return_highestLanePriority = SelectiveHydrationLanePriority;
176 + return SelectiveHydrationLane;
177 + }
178 + if ((lanes & IdleHydrationLane) !== NoLanes) {
179 + return_highestLanePriority = IdleHydrationLanePriority;
180 + return IdleHydrationLane;
181 + }
182 + const idleLanes = IdleLanes & lanes;
183 + if (idleLanes !== NoLanes) {
184 + return_highestLanePriority = IdleLanePriority;
185 + return idleLanes;
186 + }
187 + if ((OffscreenLane & lanes) !== NoLanes) {
188 + return_highestLanePriority = OffscreenLanePriority;
189 + return OffscreenLane;
190 + }
191 + if (__DEV__) {
192 + console.error('Should have found matching lanes. This is a bug in React.');
193 + }
194 + // This shouldn't be reachable, but as a fallback, return the entire bitmask.
195 + return_highestLanePriority = DefaultLanePriority;
196 + return lanes;
197 +}
198 +
199 +export function schedulerPriorityToLanePriority(
200 + schedulerPriorityLevel: ReactPriorityLevel,
201 +): LanePriority {
202 + switch (schedulerPriorityLevel) {
203 + case ImmediateSchedulerPriority:
204 + return SyncLanePriority;
205 + case UserBlockingSchedulerPriority:
206 + return InputContinuousLanePriority;
207 + case NormalSchedulerPriority:
208 + case LowSchedulerPriority:
209 + // TODO: Handle LowSchedulerPriority, somehow. Maybe the same lane as hydration.
210 + return DefaultLanePriority;
211 + case IdleSchedulerPriority:
212 + return IdleLanePriority;
213 + default:
214 + return NoLanePriority;
215 + }
216 +}
217 +
218 +export function lanePriorityToSchedulerPriority(
219 + lanePriority: LanePriority,
220 +): ReactPriorityLevel {
221 + switch (lanePriority) {
222 + case SyncLanePriority:
223 + case SyncBatchedLanePriority:
224 + return ImmediateSchedulerPriority;
225 + case InputDiscreteHydrationLanePriority:
226 + case InputDiscreteLanePriority:
227 + case InputContinuousHydrationLanePriority:
228 + case InputContinuousLanePriority:
229 + return UserBlockingSchedulerPriority;
230 + case DefaultHydrationLanePriority:
231 + case DefaultLanePriority:
232 + case TransitionHydrationPriority:
233 + case TransitionPriority:
234 + case SelectiveHydrationLanePriority:
235 + case RetryLanePriority:
236 + return NormalSchedulerPriority;
237 + case IdleHydrationLanePriority:
238 + case IdleLanePriority:
239 + case OffscreenLanePriority:
240 + return IdleSchedulerPriority;
241 + case NoLanePriority:
242 + return NoSchedulerPriority;
243 + default:
244 + invariant(
245 + false,
246 + 'Invalid update priority: %s. This is a bug in React.',
247 + lanePriority,
248 + );
249 + }
250 +}
251 +
252 +export function getNextLanes(root: FiberRoot, wipLanes: Lanes): Lanes {
253 + // Early bailout if there's no pending work left.
254 + const pendingLanes = root.pendingLanes;
255 + if (pendingLanes === NoLanes) {
256 + return_highestLanePriority = NoLanePriority;
257 + return NoLanes;
258 + }
259 +
260 + let nextLanes = NoLanes;
261 + let nextLanePriority = NoLanePriority;
262 +
263 + const expiredLanes = root.expiredLanes;
264 + const suspendedLanes = root.suspendedLanes;
265 + const pingedLanes = root.pingedLanes;
266 +
267 + // Check if any work has expired.
268 + if (expiredLanes !== NoLanes) {
269 + nextLanes = expiredLanes;
270 + nextLanePriority = return_highestLanePriority = SyncLanePriority;
271 + } else {
272 + // Do not work on any idle work until all the non-idle work has finished,
273 + // even if the work is suspended.
274 + const nonIdlePendingLanes = pendingLanes & NonIdleLanes;
275 + if (nonIdlePendingLanes !== NoLanes) {
276 + const nonIdleUnblockedLanes = nonIdlePendingLanes & ~suspendedLanes;
277 + if (nonIdleUnblockedLanes !== NoLanes) {
278 + nextLanes = getHighestPriorityLanes(nonIdleUnblockedLanes);
279 + nextLanePriority = return_highestLanePriority;
280 + } else {
281 + const nonIdlePingedLanes = nonIdlePendingLanes & pingedLanes;
282 + if (nonIdlePingedLanes !== NoLanes) {
283 + nextLanes = getHighestPriorityLanes(nonIdlePingedLanes);
284 + nextLanePriority = return_highestLanePriority;
285 + }
286 + }
287 + } else {
288 + // The only remaining work is Idle.
289 + const unblockedLanes = pendingLanes & ~suspendedLanes;
290 + if (unblockedLanes !== NoLanes) {
291 + nextLanes = getHighestPriorityLanes(unblockedLanes);
292 + nextLanePriority = return_highestLanePriority;
293 + } else {
294 + if (pingedLanes !== NoLanes) {
295 + nextLanes = getHighestPriorityLanes(pingedLanes);
296 + nextLanePriority = return_highestLanePriority;
297 + }
298 + }
299 + }
300 + }
301 +
302 + if (nextLanes === NoLanes) {
303 + // This should only be reachable if we're suspended
304 + // TODO: Consider warning in this path if a fallback timer is not scheduled.
305 + return NoLanes;
306 + }
307 +
308 + // If there are higher priority lanes, we'll include them even if they
309 + // are suspended.
310 + nextLanes = pendingLanes & getEqualOrHigherPriorityLanes(nextLanes);
311 +
312 + // If we're already in the middle of a render, switching lanes will interrupt
313 + // it and we'll lose our progress. We should only do this if the new lanes are
314 + // higher priority.
315 + if (
316 + wipLanes !== NoLanes &&
317 + wipLanes !== nextLanes &&
318 + // If we already suspended with a delay, then interrupting is fine. Don't
319 + // bother waiting until the root is complete.
320 + (wipLanes & suspendedLanes) === NoLanes
321 + ) {
322 + getHighestPriorityLanes(wipLanes);
323 + const wipLanePriority = return_highestLanePriority;
324 + if (nextLanePriority <= wipLanePriority) {
325 + return wipLanes;
326 + } else {
327 + return_highestLanePriority = nextLanePriority;
328 + }
329 + }
330 +
331 + // Check for entangled lanes and add them to the batch.
332 + //
333 + // A lane is said to be entangled with another when it's not allowed to render
334 + // in a batch that does not also include the other lane. Typically we do this
335 + // when multiple updates have the same source, and we only want to respond to
336 + // the most recent event from that source.
337 + //
338 + // Note that we apply entanglements *after* checking for partial work above.
339 + // This means that if a lane is entangled during an interleaved event while
340 + // it's already rendering, we won't interrupt it. This is intentional, since
341 + // entanglement is usually "best effort": we'll try our best to render the
342 + // lanes in the same batch, but it's not worth throwing out partially
343 + // completed work in order to do it.
344 + //
345 + // For those exceptions where entanglement is semantically important, like
346 + // useMutableSource, we should ensure that there is no partial work at the
347 + // time we apply the entanglement.
348 + const entangledLanes = root.entangledLanes;
349 + if (entangledLanes !== NoLanes) {
350 + const entanglements = root.entanglements;
351 + let lanes = nextLanes & entangledLanes;
352 + while (lanes > 0) {
353 + const index = pickArbitraryLaneIndex(lanes);
354 + const lane = 1 << index;
355 +
356 + nextLanes |= entanglements[index];
357 +
358 + lanes &= ~lane;
359 + }
360 + }
361 +
362 + return nextLanes;
363 +}
364 +
365 +export function getMostRecentEventTime(root: FiberRoot, lanes: Lanes): number {
366 + const eventTimes = root.eventTimes;
367 +
368 + let mostRecentEventTime = NoTimestamp;
369 + while (lanes > 0) {
370 + const index = pickArbitraryLaneIndex(lanes);
371 + const lane = 1 << index;
372 +
373 + const eventTime = eventTimes[index];
374 + if (eventTime > mostRecentEventTime) {
375 + mostRecentEventTime = eventTime;
376 + }
377 +
378 + lanes &= ~lane;
379 + }
380 +
381 + return mostRecentEventTime;
382 +}
383 +
384 +function computeExpirationTime(lane: Lane, currentTime: number) {
385 + // TODO: Expiration heuristic is constant per lane, so could use a map.
386 + getHighestPriorityLanes(lane);
387 + const priority = return_highestLanePriority;
388 + if (priority >= InputContinuousLanePriority) {
389 + // User interactions should expire slightly more quickly.
390 + //
391 + // NOTE: This is set to the corresponding constant as in Scheduler.js. When
392 + // we made it larger, a product metric in www regressed, suggesting there's
393 + // a user interaction that's being starved by a series of synchronous
394 + // updates. If that theory is correct, the proper solution is to fix the
395 + // starvation. However, this scenario supports the idea that expiration
396 + // times are an important safeguard when starvation does happen.
397 + //
398 + // Also note that, in the case of user input specifically, this will soon no
399 + // longer be an issue because we plan to make user input synchronous by
400 + // default (until you enter `startTransition`, of course.)
401 + //
402 + // If weren't planning to make these updates synchronous soon anyway, I
403 + // would probably make this number a configurable parameter.
404 + return currentTime + 250;
405 + } else if (priority >= TransitionPriority) {
406 + return currentTime + 5000;
407 + } else {
408 + // Anything idle priority or lower should never expire.
409 + return NoTimestamp;
410 + }
411 +}
412 +
413 +export function markStarvedLanesAsExpired(
414 + root: FiberRoot,
415 + currentTime: number,
416 +): void {
417 + // TODO: This gets called every time we yield. We can optimize by storing
418 + // the earliest expiration time on the root. Then use that to quickly bail out
419 + // of this function.
420 +
421 + const pendingLanes = root.pendingLanes;
422 + const suspendedLanes = root.suspendedLanes;
423 + const pingedLanes = root.pingedLanes;
424 + const expirationTimes = root.expirationTimes;
425 +
426 + // Iterate through the pending lanes and check if we've reached their
427 + // expiration time. If so, we'll assume the update is being starved and mark
428 + // it as expired to force it to finish.
429 + let lanes = pendingLanes;
430 + while (lanes > 0) {
431 + const index = pickArbitraryLaneIndex(lanes);
432 + const lane = 1 << index;
433 +
434 + const expirationTime = expirationTimes[index];
435 + if (expirationTime === NoTimestamp) {
436 + // Found a pending lane with no expiration time. If it's not suspended, or
437 + // if it's pinged, assume it's CPU-bound. Compute a new expiration time
438 + // using the current time.
439 + if (
440 + (lane & suspendedLanes) === NoLanes ||
441 + (lane & pingedLanes) !== NoLanes
442 + ) {
443 + // Assumes timestamps are monotonically increasing.
444 + expirationTimes[index] = computeExpirationTime(lane, currentTime);
445 + }
446 + } else if (expirationTime <= currentTime) {
447 + // This lane expired
448 + root.expiredLanes |= lane;
449 + }
450 +
451 + lanes &= ~lane;
452 + }
453 +}
454 +
455 +// This returns the highest priority pending lanes regardless of whether they
456 +// are suspended.
457 +export function getHighestPriorityPendingLanes(root: FiberRoot) {
458 + return getHighestPriorityLanes(root.pendingLanes);
459 +}
460 +
461 +export function getLanesToRetrySynchronouslyOnError(root: FiberRoot): Lanes {
462 + const everythingButOffscreen = root.pendingLanes & ~OffscreenLane;
463 + if (everythingButOffscreen !== NoLanes) {
464 + return everythingButOffscreen;
465 + }
466 + if (everythingButOffscreen & OffscreenLane) {
467 + return OffscreenLane;
468 + }
469 + return NoLanes;
470 +}
471 +
472 +export function returnNextLanesPriority() {
473 + return return_highestLanePriority;
474 +}
475 +export function includesNonIdleWork(lanes: Lanes) {
476 + return (lanes & NonIdleLanes) !== NoLanes;
477 +}
478 +export function includesOnlyRetries(lanes: Lanes) {
479 + return (lanes & RetryLanes) === lanes;
480 +}
481 +export function includesOnlyTransitions(lanes: Lanes) {
482 + return (lanes & TransitionLanes) === lanes;
483 +}
484 +
485 +// To ensure consistency across multiple updates in the same event, this should
486 +// be a pure function, so that it always returns the same lane for given inputs.
487 +export function findUpdateLane(
488 + lanePriority: LanePriority,
489 + wipLanes: Lanes,
490 +): Lane {
491 + switch (lanePriority) {
492 + case NoLanePriority:
493 + break;
494 + case SyncLanePriority:
495 + return SyncLane;
496 + case SyncBatchedLanePriority:
497 + return SyncBatchedLane;
498 + case InputDiscreteLanePriority: {
499 + const lane = pickArbitraryLane(InputDiscreteLanes & ~wipLanes);
500 + if (lane === NoLane) {
501 + // Shift to the next priority level
502 + return findUpdateLane(InputContinuousLanePriority, wipLanes);
503 + }
504 + return lane;
505 + }
506 + case InputContinuousLanePriority: {
507 + const lane = pickArbitraryLane(InputContinuousLanes & ~wipLanes);
508 + if (lane === NoLane) {
509 + // Shift to the next priority level
510 + return findUpdateLane(DefaultLanePriority, wipLanes);
511 + }
512 + return lane;
513 + }
514 + case DefaultLanePriority: {
515 + let lane = pickArbitraryLane(DefaultLanes & ~wipLanes);
516 + if (lane === NoLane) {
517 + // If all the default lanes are already being worked on, look for a
518 + // lane in the transition range.
519 + lane = pickArbitraryLane(TransitionLanes & ~wipLanes);
520 + if (lane === NoLane) {
521 + // All the transition lanes are taken, too. This should be very
522 + // rare, but as a last resort, pick a default lane. This will have
523 + // the effect of interrupting the current work-in-progress render.
524 + lane = pickArbitraryLane(DefaultLanes);
525 + }
526 + }
527 + return lane;
528 + }
529 + case TransitionPriority: // Should be handled by findTransitionLane instead
530 + case RetryLanePriority: // Should be handled by findRetryLane instead
531 + break;
532 + case IdleLanePriority:
533 + let lane = pickArbitraryLane(IdleLanes & ~wipLanes);
534 + if (lane === NoLane) {
535 + lane = pickArbitraryLane(IdleLanes);
536 + }
537 + return lane;
538 + default:
539 + // The remaining priorities are not valid for updates
540 + break;
541 + }
542 + invariant(
543 + false,
544 + 'Invalid update priority: %s. This is a bug in React.',
545 + lanePriority,
546 + );
547 +}
548 +
549 +// To ensure consistency across multiple updates in the same event, this should
550 +// be pure function, so that it always returns the same lane for given inputs.
551 +export function findTransitionLane(wipLanes: Lanes, pendingLanes: Lanes): Lane {
552 + // First look for lanes that are completely unclaimed, i.e. have no
553 + // pending work.
554 + let lane = pickArbitraryLane(TransitionLanes & ~pendingLanes);
555 + if (lane === NoLane) {
556 + // If all lanes have pending work, look for a lane that isn't currently
557 + // being worked on.
558 + lane = pickArbitraryLane(TransitionLanes & ~wipLanes);
559 + if (lane === NoLane) {
560 + // If everything is being worked on, pick any lane. This has the
561 + // effect of interrupting the current work-in-progress.
562 + lane = pickArbitraryLane(TransitionLanes);
563 + }
564 + }
565 + return lane;
566 +}
567 +
568 +// To ensure consistency across multiple updates in the same event, this should
569 +// be pure function, so that it always returns the same lane for given inputs.
570 +export function findRetryLane(wipLanes: Lanes): Lane {
571 + // This is a fork of `findUpdateLane` designed specifically for Suspense
572 + // "retries" — a special update that attempts to flip a Suspense boundary
573 + // from its placeholder state to its primary/resolved state.
574 + let lane = pickArbitraryLane(RetryLanes & ~wipLanes);
575 + if (lane === NoLane) {
576 + lane = pickArbitraryLane(RetryLanes);
577 + }
578 + return lane;
579 +}
580 +
581 +function getHighestPriorityLane(lanes: Lanes) {
582 + return lanes & -lanes;
583 +}
584 +
585 +function getLowestPriorityLane(lanes: Lanes): Lane {
586 + // This finds the most significant non-zero bit.
587 + const index = 31 - clz32(lanes);
588 + return index < 0 ? NoLanes : 1 << index;
589 +}
590 +
591 +function getEqualOrHigherPriorityLanes(lanes: Lanes | Lane): Lanes {
592 + return (getLowestPriorityLane(lanes) << 1) - 1;
593 +}
594 +
595 +export function pickArbitraryLane(lanes: Lanes): Lane {
596 + // This wrapper function gets inlined. Only exists so to communicate that it
597 + // doesn't matter which bit is selected; you can pick any bit without
598 + // affecting the algorithms where its used. Here I'm using
599 + // getHighestPriorityLane because it requires the fewest operations.
600 + return getHighestPriorityLane(lanes);
601 +}
602 +
603 +function pickArbitraryLaneIndex(lanes: Lanes) {
604 + return 31 - clz32(lanes);
605 +}
606 +
607 +function laneToIndex(lane: Lane) {
608 + return pickArbitraryLaneIndex(lane);
609 +}
610 +
611 +export function includesSomeLane(a: Lanes | Lane, b: Lanes | Lane) {
612 + return (a & b) !== NoLanes;
613 +}
614 +
615 +export function isSubsetOfLanes(set: Lanes, subset: Lanes | Lane) {
616 + return (set & subset) === subset;
617 +}
618 +
619 +export function mergeLanes(a: Lanes | Lane, b: Lanes | Lane): Lanes {
620 + return a | b;
621 +}
622 +
623 +export function removeLanes(set: Lanes, subset: Lanes | Lane): Lanes {
624 + return set & ~subset;
625 +}
626 +
627 +// Seems redundant, but it changes the type from a single lane (used for
628 +// updates) to a group of lanes (used for flushing work).
629 +export function laneToLanes(lane: Lane): Lanes {
630 + return lane;
631 +}
632 +
633 +export function higherPriorityLane(a: Lane, b: Lane) {
634 + // This works because the bit ranges decrease in priority as you go left.
635 + return a !== NoLane && a < b ? a : b;
636 +}
637 +
638 +export function higherLanePriority(
639 + a: LanePriority,
640 + b: LanePriority,
641 +): LanePriority {
642 + return a !== NoLanePriority && a > b ? a : b;
643 +}
644 +
645 +export function createLaneMap<T>(initial: T): LaneMap<T> {
646 + // Intentionally pushing one by one.
647 + // https://v8.dev/blog/elements-kinds#avoid-creating-holes
648 + const laneMap = [];
649 + for (let i = 0; i < TotalLanes; i++) {
650 + laneMap.push(initial);
651 + }
652 + return laneMap;
653 +}
654 +
655 +export function markRootUpdated(
656 + root: FiberRoot,
657 + updateLane: Lane,
658 + eventTime: number,
659 +) {
660 + root.pendingLanes |= updateLane;
661 +
662 + // TODO: Theoretically, any update to any lane can unblock any other lane. But
663 + // it's not practical to try every single possible combination. We need a
664 + // heuristic to decide which lanes to attempt to render, and in which batches.
665 + // For now, we use the same heuristic as in the old ExpirationTimes model:
666 + // retry any lane at equal or lower priority, but don't try updates at higher
667 + // priority without also including the lower priority updates. This works well
668 + // when considering updates across different priority levels, but isn't
669 + // sufficient for updates within the same priority, since we want to treat
670 + // those updates as parallel.
671 +
672 + // Unsuspend any update at equal or lower priority.
673 + const higherPriorityLanes = updateLane - 1; // Turns 0b1000 into 0b0111
674 +
675 + root.suspendedLanes &= higherPriorityLanes;
676 + root.pingedLanes &= higherPriorityLanes;
677 +
678 + const eventTimes = root.eventTimes;
679 + const index = laneToIndex(updateLane);
680 + // We can always overwrite an existing timestamp because we prefer the most
681 + // recent event, and we assume time is monotonically increasing.
682 + eventTimes[index] = eventTime;
683 +}
684 +
685 +export function markRootSuspended(root: FiberRoot, suspendedLanes: Lanes) {
686 + root.suspendedLanes |= suspendedLanes;
687 + root.pingedLanes &= ~suspendedLanes;
688 +
689 + // The suspended lanes are no longer CPU-bound. Clear their expiration times.
690 + const expirationTimes = root.expirationTimes;
691 + let lanes = suspendedLanes;
692 + while (lanes > 0) {
693 + const index = pickArbitraryLaneIndex(lanes);
694 + const lane = 1 << index;
695 +
696 + expirationTimes[index] = NoTimestamp;
697 +
698 + lanes &= ~lane;
699 + }
700 +}
701 +
702 +export function markRootPinged(
703 + root: FiberRoot,
704 + pingedLanes: Lanes,
705 + eventTime: number,
706 +) {
707 + root.pingedLanes |= root.suspendedLanes & pingedLanes;
708 +}
709 +
710 +export function markRootExpired(root: FiberRoot, expiredLanes: Lanes) {
711 + root.expiredLanes |= expiredLanes & root.pendingLanes;
712 +}
713 +
714 +export function markDiscreteUpdatesExpired(root: FiberRoot) {
715 + root.expiredLanes |= InputDiscreteLanes & root.pendingLanes;
716 +}
717 +
718 +export function hasDiscreteLanes(lanes: Lanes) {
719 + return (lanes & InputDiscreteLanes) !== NoLanes;
720 +}
721 +
722 +export function markRootMutableRead(root: FiberRoot, updateLane: Lane) {
723 + root.mutableReadLanes |= updateLane & root.pendingLanes;
724 +}
725 +
726 +export function markRootFinished(root: FiberRoot, remainingLanes: Lanes) {
727 + const noLongerPendingLanes = root.pendingLanes & ~remainingLanes;
728 +
729 + root.pendingLanes = remainingLanes;
730 +
731 + // Let's try everything again
732 + root.suspendedLanes = 0;
733 + root.pingedLanes = 0;
734 +
735 + root.expiredLanes &= remainingLanes;
736 + root.mutableReadLanes &= remainingLanes;
737 +
738 + root.entangledLanes &= remainingLanes;
739 +
740 + const entanglements = root.entanglements;
741 + const eventTimes = root.eventTimes;
742 + const expirationTimes = root.expirationTimes;
743 +
744 + // Clear the lanes that no longer have pending work
745 + let lanes = noLongerPendingLanes;
746 + while (lanes > 0) {
747 + const index = pickArbitraryLaneIndex(lanes);
748 + const lane = 1 << index;
749 +
750 + entanglements[index] = NoLanes;
751 + eventTimes[index] = NoTimestamp;
752 + expirationTimes[index] = NoTimestamp;
753 +
754 + lanes &= ~lane;
755 + }
756 +}
757 +
758 +export function markRootEntangled(root: FiberRoot, entangledLanes: Lanes) {
759 + root.entangledLanes |= entangledLanes;
760 +
761 + const entanglements = root.entanglements;
762 + let lanes = entangledLanes;
763 + while (lanes > 0) {
764 + const index = pickArbitraryLaneIndex(lanes);
765 + const lane = 1 << index;
766 +
767 + entanglements[index] |= entangledLanes;
768 +
769 + lanes &= ~lane;
770 + }
771 +}
772 +
773 +export function getBumpedLaneForHydration(
774 + root: FiberRoot,
775 + renderLanes: Lanes,
776 +): Lane {
777 + getHighestPriorityLanes(renderLanes);
778 + const highestLanePriority = return_highestLanePriority;
779 +
780 + let lane;
781 + switch (highestLanePriority) {
782 + case SyncLanePriority:
783 + case SyncBatchedLanePriority:
784 + lane = NoLane;
785 + break;
786 + case InputDiscreteHydrationLanePriority:
787 + case InputDiscreteLanePriority:
788 + lane = InputDiscreteHydrationLane;
789 + break;
790 + case InputContinuousHydrationLanePriority:
791 + case InputContinuousLanePriority:
792 + lane = InputContinuousHydrationLane;
793 + break;
794 + case DefaultHydrationLanePriority:
795 + case DefaultLanePriority:
796 + lane = DefaultHydrationLane;
797 + break;
798 + case TransitionHydrationPriority:
799 + case TransitionPriority:
800 + lane = TransitionHydrationLane;
801 + break;
802 + case RetryLanePriority:
803 + // Shouldn't be reachable under normal circumstances, so there's no
804 + // dedicated lane for retry priority. Use the one for long transitions.
805 + lane = TransitionHydrationLane;
806 + break;
807 + case SelectiveHydrationLanePriority:
808 + lane = SelectiveHydrationLane;
809 + break;
810 + case IdleHydrationLanePriority:
811 + case IdleLanePriority:
812 + lane = IdleHydrationLane;
813 + break;
814 + case OffscreenLanePriority:
815 + case NoLanePriority:
816 + lane = NoLane;
817 + break;
818 + default:
819 + invariant(false, 'Invalid lane: %s. This is a bug in React.', lane);
820 + }
821 +
822 + // Check if the lane we chose is suspended. If so, that indicates that we
823 + // already attempted and failed to hydrate at that level. Also check if we're
824 + // already rendering that lane, which is rare but could happen.
825 + if ((lane & (root.suspendedLanes | renderLanes)) !== NoLane) {
826 + // Give up trying to hydrate and fall back to client render.
827 + return NoLane;
828 + }
829 +
830 + return lane;
831 +}
832 +
833 +const clz32 = Math.clz32 ? Math.clz32 : clz32Fallback;
834 +
835 +// Count leading zeros. Only used on lanes, so assume input is an integer.
836 +// Based on:
837 +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/clz32
838 +const log = Math.log;
839 +const LN2 = Math.LN2;
840 +function clz32Fallback(lanes: Lanes | Lane) {
841 + if (lanes === 0) {
842 + return 32;
843 + }
844 + return (31 - ((log(lanes) / LN2) | 0)) | 0;
845 +}
packages/react-reconciler/src/ReactFiberNewContext.new.js
+2 -2
@@ -10,7 +10,7 @@
10 import type {ReactContext} from 'shared/ReactTypes';
11 import type {Fiber, ContextDependency} from './ReactInternalTypes';
12 import type {StackCursor} from './ReactFiberStack.new';
13 -import type {Lanes} from './ReactFiberLane';
13 +import type {Lanes} from './ReactFiberLane.new';
14
15 import {isPrimaryRenderer} from './ReactFiberHostConfig';
16 import {createCursor, push, pop} from './ReactFiberStack.new';
@@ -27,7 +27,7 @@ import {
27 includesSomeLane,
28 mergeLanes,
29 pickArbitraryLane,
30 -} from './ReactFiberLane';
30 +} from './ReactFiberLane.new';
31
32 import invariant from 'shared/invariant';
33 import is from 'shared/objectIs';
packages/react-reconciler/src/ReactFiberNewContext.old.js
+2 -2
@@ -10,7 +10,7 @@
10 import type {ReactContext} from 'shared/ReactTypes';
11 import type {Fiber, ContextDependency} from './ReactInternalTypes';
12 import type {StackCursor} from './ReactFiberStack.old';
13 -import type {Lanes} from './ReactFiberLane';
13 +import type {Lanes} from './ReactFiberLane.old';
14
15 import {isPrimaryRenderer} from './ReactFiberHostConfig';
16 import {createCursor, push, pop} from './ReactFiberStack.old';
@@ -27,7 +27,7 @@ import {
27 includesSomeLane,
28 mergeLanes,
29 pickArbitraryLane,
30 -} from './ReactFiberLane';
30 +} from './ReactFiberLane.old';
31
32 import invariant from 'shared/invariant';
33 import is from 'shared/objectIs';
packages/react-reconciler/src/ReactFiberOffscreenComponent.js
+1 -1
@@ -8,7 +8,7 @@
8 */
9
10 import type {ReactNodeList} from 'shared/ReactTypes';
11 -import type {Lanes} from './ReactFiberLane';
11 +import type {Lanes} from './ReactFiberLane.old';
12
13 export type OffscreenProps = {|
14 // TODO: Pick an API before exposing the Offscreen type. I've chosen an enum
packages/react-reconciler/src/ReactFiberReconciler.new.js
+2 -2
@@ -19,7 +19,7 @@ import type {
19 import type {RendererInspectionConfig} from './ReactFiberHostConfig';
20 import {FundamentalComponent} from './ReactWorkTags';
21 import type {ReactNodeList} from 'shared/ReactTypes';
22 -import type {Lane, LanePriority} from './ReactFiberLane';
22 +import type {Lane, LanePriority} from './ReactFiberLane.new';
23 import type {SuspenseState} from './ReactFiberSuspenseComponent.new';
24
25 import {
@@ -82,7 +82,7 @@ import {
82 higherPriorityLane,
83 getCurrentUpdateLanePriority,
84 setCurrentUpdateLanePriority,
85 -} from './ReactFiberLane';
85 +} from './ReactFiberLane.new';
86 import {
87 scheduleRefresh,
88 scheduleRoot,
packages/react-reconciler/src/ReactFiberReconciler.old.js
+2 -2
@@ -19,7 +19,7 @@ import type {
19 import type {RendererInspectionConfig} from './ReactFiberHostConfig';
20 import {FundamentalComponent} from './ReactWorkTags';
21 import type {ReactNodeList} from 'shared/ReactTypes';
22 -import type {Lane, LanePriority} from './ReactFiberLane';
22 +import type {Lane, LanePriority} from './ReactFiberLane.old';
23 import type {SuspenseState} from './ReactFiberSuspenseComponent.old';
24
25 import {
@@ -82,7 +82,7 @@ import {
82 higherPriorityLane,
83 getCurrentUpdateLanePriority,
84 setCurrentUpdateLanePriority,
85 -} from './ReactFiberLane';
85 +} from './ReactFiberLane.old';
86 import {
87 scheduleRefresh,
88 scheduleRoot,
packages/react-reconciler/src/ReactFiberRoot.new.js
+1 -1
@@ -17,7 +17,7 @@ import {
17 NoLanePriority,
18 NoTimestamp,
19 createLaneMap,
20 -} from './ReactFiberLane';
20 +} from './ReactFiberLane.new';
21 import {
22 enableSchedulerTracing,
23 enableSuspenseCallback,
packages/react-reconciler/src/ReactFiberRoot.old.js
+1 -1
@@ -17,7 +17,7 @@ import {
17 NoLanePriority,
18 NoTimestamp,
19 createLaneMap,
20 -} from './ReactFiberLane';
20 +} from './ReactFiberLane.old';
21 import {
22 enableSchedulerTracing,
23 enableSuspenseCallback,
packages/react-reconciler/src/ReactFiberSuspenseComponent.new.js
+1 -1
@@ -10,7 +10,7 @@
10 import type {ReactNodeList, Wakeable} from 'shared/ReactTypes';
11 import type {Fiber} from './ReactInternalTypes';
12 import type {SuspenseInstance} from './ReactFiberHostConfig';
13 -import type {Lane} from './ReactFiberLane';
13 +import type {Lane} from './ReactFiberLane.new';
14 import {SuspenseComponent, SuspenseListComponent} from './ReactWorkTags';
15 import {NoFlags, DidCapture} from './ReactFiberFlags';
16 import {
packages/react-reconciler/src/ReactFiberSuspenseComponent.old.js
+1 -1
@@ -10,7 +10,7 @@
10 import type {ReactNodeList, Wakeable} from 'shared/ReactTypes';
11 import type {Fiber} from './ReactInternalTypes';
12 import type {SuspenseInstance} from './ReactFiberHostConfig';
13 -import type {Lane} from './ReactFiberLane';
13 +import type {Lane} from './ReactFiberLane.old';
14 import {SuspenseComponent, SuspenseListComponent} from './ReactWorkTags';
15 import {NoFlags, DidCapture} from './ReactFiberFlags';
16 import {
packages/react-reconciler/src/ReactFiberThrow.new.js
+2 -2
@@ -9,7 +9,7 @@
9
10 import type {Fiber} from './ReactInternalTypes';
11 import type {FiberRoot} from './ReactInternalTypes';
12 -import type {Lane, Lanes} from './ReactFiberLane';
12 +import type {Lane, Lanes} from './ReactFiberLane.new';
13 import type {CapturedValue} from './ReactCapturedValue';
14 import type {Update} from './ReactUpdateQueue.new';
15 import type {Wakeable} from 'shared/ReactTypes';
@@ -67,7 +67,7 @@ import {
67 includesSomeLane,
68 mergeLanes,
69 pickArbitraryLane,
70 -} from './ReactFiberLane';
70 +} from './ReactFiberLane.new';
71
72 const PossiblyWeakMap = typeof WeakMap === 'function' ? WeakMap : Map;
73
packages/react-reconciler/src/ReactFiberThrow.old.js
+2 -2
@@ -9,7 +9,7 @@
9
10 import type {Fiber} from './ReactInternalTypes';
11 import type {FiberRoot} from './ReactInternalTypes';
12 -import type {Lane, Lanes} from './ReactFiberLane';
12 +import type {Lane, Lanes} from './ReactFiberLane.old';
13 import type {CapturedValue} from './ReactCapturedValue';
14 import type {Update} from './ReactUpdateQueue.old';
15 import type {Wakeable} from 'shared/ReactTypes';
@@ -67,7 +67,7 @@ import {
67 includesSomeLane,
68 mergeLanes,
69 pickArbitraryLane,
70 -} from './ReactFiberLane';
70 +} from './ReactFiberLane.old';
71
72 const PossiblyWeakMap = typeof WeakMap === 'function' ? WeakMap : Map;
73
packages/react-reconciler/src/ReactFiberUnwindWork.new.js
+1 -1
@@ -8,7 +8,7 @@
8 */
9
10 import type {Fiber} from './ReactInternalTypes';
11 -import type {Lanes} from './ReactFiberLane';
11 +import type {Lanes} from './ReactFiberLane.new';
12 import type {SuspenseState} from './ReactFiberSuspenseComponent.new';
13
14 import {resetWorkInProgressVersions as resetMutableSourceWorkInProgressVersions} from './ReactMutableSource.new';
packages/react-reconciler/src/ReactFiberUnwindWork.old.js
+1 -1
@@ -8,7 +8,7 @@
8 */
9
10 import type {Fiber} from './ReactInternalTypes';
11 -import type {Lanes} from './ReactFiberLane';
11 +import type {Lanes} from './ReactFiberLane.old';
12 import type {SuspenseState} from './ReactFiberSuspenseComponent.old';
13
14 import {resetWorkInProgressVersions as resetMutableSourceWorkInProgressVersions} from './ReactMutableSource.old';
packages/react-reconciler/src/ReactFiberWorkLoop.new.js
+2 -2
@@ -9,7 +9,7 @@
9
10 import type {Thenable, Wakeable} from 'shared/ReactTypes';
11 import type {Fiber, FiberRoot} from './ReactInternalTypes';
12 -import type {Lanes, Lane} from './ReactFiberLane';
12 +import type {Lanes, Lane} from './ReactFiberLane.new';
13 import type {ReactPriorityLevel} from './ReactInternalTypes';
14 import type {Interaction} from 'scheduler/src/Tracing';
15 import type {SuspenseState} from './ReactFiberSuspenseComponent.new';
@@ -173,7 +173,7 @@ import {
173 markRootFinished,
174 schedulerPriorityToLanePriority,
175 lanePriorityToSchedulerPriority,
176 -} from './ReactFiberLane';
176 +} from './ReactFiberLane.new';
177 import {requestCurrentTransition, NoTransition} from './ReactFiberTransition';
178 import {beginWork as originalBeginWork} from './ReactFiberBeginWork.new';
179 import {completeWork} from './ReactFiberCompleteWork.new';
packages/react-reconciler/src/ReactFiberWorkLoop.old.js
+2 -2
@@ -9,7 +9,7 @@
9
10 import type {Thenable, Wakeable} from 'shared/ReactTypes';
11 import type {Fiber, FiberRoot} from './ReactInternalTypes';
12 -import type {Lanes, Lane} from './ReactFiberLane';
12 +import type {Lanes, Lane} from './ReactFiberLane.old';
13 import type {ReactPriorityLevel} from './ReactInternalTypes';
14 import type {Interaction} from 'scheduler/src/Tracing';
15 import type {SuspenseState} from './ReactFiberSuspenseComponent.old';
@@ -173,7 +173,7 @@ import {
173 markRootFinished,
174 schedulerPriorityToLanePriority,
175 lanePriorityToSchedulerPriority,
176 -} from './ReactFiberLane';
176 +} from './ReactFiberLane.old';
177 import {requestCurrentTransition, NoTransition} from './ReactFiberTransition';
178 import {beginWork as originalBeginWork} from './ReactFiberBeginWork.old';
179 import {completeWork} from './ReactFiberCompleteWork.old';
packages/react-reconciler/src/ReactInternalTypes.js
+1 -1
@@ -20,7 +20,7 @@ import type {SuspenseInstance} from './ReactFiberHostConfig';
20 import type {WorkTag} from './ReactWorkTags';
21 import type {TypeOfMode} from './ReactTypeOfMode';
22 import type {Flags} from './ReactFiberFlags';
23 -import type {Lane, LanePriority, Lanes, LaneMap} from './ReactFiberLane';
23 +import type {Lane, LanePriority, Lanes, LaneMap} from './ReactFiberLane.old';
24 import type {RootTag} from './ReactRootTags';
25 import type {TimeoutHandle, NoTimeout} from './ReactFiberHostConfig';
26 import type {Wakeable} from 'shared/ReactTypes';
packages/react-reconciler/src/ReactUpdateQueue.new.js
+7 -2
@@ -85,9 +85,14 @@
85 // resources, but the final state is always the same.
86
87 import type {Fiber} from './ReactInternalTypes';
88 -import type {Lanes, Lane} from './ReactFiberLane';
88 +import type {Lanes, Lane} from './ReactFiberLane.new';
89
90 -import {NoLane, NoLanes, isSubsetOfLanes, mergeLanes} from './ReactFiberLane';
90 +import {
91 + NoLane,
92 + NoLanes,
93 + isSubsetOfLanes,
94 + mergeLanes,
95 +} from './ReactFiberLane.new';
96 import {
97 enterDisallowedContextReadInDEV,
98 exitDisallowedContextReadInDEV,
packages/react-reconciler/src/ReactUpdateQueue.old.js
+7 -2
@@ -85,9 +85,14 @@
85 // resources, but the final state is always the same.
86
87 import type {Fiber} from './ReactInternalTypes';
88 -import type {Lanes, Lane} from './ReactFiberLane';
88 +import type {Lanes, Lane} from './ReactFiberLane.old';
89
90 -import {NoLane, NoLanes, isSubsetOfLanes, mergeLanes} from './ReactFiberLane';
90 +import {
91 + NoLane,
92 + NoLanes,
93 + isSubsetOfLanes,
94 + mergeLanes,
95 +} from './ReactFiberLane.old';
96 import {
97 enterDisallowedContextReadInDEV,
98 exitDisallowedContextReadInDEV,
packages/react-reconciler/src/SchedulerWithReactIntegration.new.js
+1 -1
@@ -22,7 +22,7 @@ import {
22 SyncLanePriority,
23 getCurrentUpdateLanePriority,
24 setCurrentUpdateLanePriority,
25 -} from './ReactFiberLane';
25 +} from './ReactFiberLane.new';
26
27 const {
28 unstable_runWithPriority: Scheduler_runWithPriority,
packages/react-reconciler/src/SchedulerWithReactIntegration.old.js
+1 -1
@@ -22,7 +22,7 @@ import {
22 SyncLanePriority,
23 getCurrentUpdateLanePriority,
24 setCurrentUpdateLanePriority,
25 -} from './ReactFiberLane';
25 +} from './ReactFiberLane.old';
26
27 const {
28 unstable_runWithPriority: Scheduler_runWithPriority,
packages/react-reconciler/src/SchedulingProfiler.js
+1 -1
@@ -7,7 +7,7 @@
7 * @flow
8 */
9
10 -import type {Lane, Lanes} from './ReactFiberLane';
10 +import type {Lane, Lanes} from './ReactFiberLane.old';
11 import type {Fiber} from './ReactInternalTypes';
12 import type {Wakeable} from 'shared/ReactTypes';
13