Skip to content

Commit b2dc5de

Browse files
committed
Revert "Fix: Detect infinite update loops caused by render phase updates (#26625)" (#27027)
This reverts commit 822386f. This broke a number of tests when synced internally. We'll need to investigate the breakages before relanding this. DiffTrain build for commit 7f362de.
1 parent f8f734e commit b2dc5de

File tree

13 files changed

+227
-899
lines changed

13 files changed

+227
-899
lines changed

compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react-test-renderer/cjs/ReactTestRenderer-dev.js

Lines changed: 15 additions & 149 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* @noflow
88
* @nolint
99
* @preventMunge
10-
* @generated SignedSource<<b3edba4ee6aa87997395f161d846a4b0>>
10+
* @generated SignedSource<<adf921170475fb87731c699acf7c0c8f>>
1111
*/
1212

1313
'use strict';
@@ -1584,7 +1584,7 @@ function createLaneMap(initial) {
15841584

15851585
return laneMap;
15861586
}
1587-
function markRootUpdated$1(root, updateLane) {
1587+
function markRootUpdated(root, updateLane) {
15881588
root.pendingLanes |= updateLane; // If there are any suspended transitions, it's possible this new update
15891589
// could unblock them. Clear the suspended lanes so that we can try rendering
15901590
// them again.
@@ -1617,7 +1617,7 @@ function markRootSuspended$1(root, suspendedLanes) {
16171617
lanes &= ~lane;
16181618
}
16191619
}
1620-
function markRootPinged$1(root, pingedLanes) {
1620+
function markRootPinged(root, pingedLanes) {
16211621
root.pingedLanes |= root.suspendedLanes & pingedLanes;
16221622
}
16231623
function markRootFinished(root, remainingLanes) {
@@ -6031,21 +6031,6 @@ function ensureRootIsScheduled(root) {
60316031
ReactCurrentActQueue$2.didScheduleLegacyUpdate = true;
60326032
}
60336033
}
6034-
6035-
function unscheduleAllRoots() {
6036-
// This is only done in a fatal error situation, as a last resort to prevent
6037-
// an infinite render loop.
6038-
var root = firstScheduledRoot;
6039-
6040-
while (root !== null) {
6041-
var next = root.next;
6042-
root.next = null;
6043-
root = next;
6044-
}
6045-
6046-
firstScheduledRoot = lastScheduledRoot = null;
6047-
}
6048-
60496034
function flushSyncWorkOnAllRoots() {
60506035
// This is allowed to be called synchronously, but the caller should check
60516036
// the execution context first.
@@ -6074,49 +6059,11 @@ function flushSyncWorkAcrossRoots_impl(onlyLegacy) {
60746059
var workInProgressRootRenderLanes = getWorkInProgressRootRenderLanes(); // There may or may not be synchronous work scheduled. Let's check.
60756060

60766061
var didPerformSomeWork;
6077-
var nestedUpdatePasses = 0;
60786062
var errors = null;
60796063
isFlushingWork = true;
60806064

60816065
do {
6082-
didPerformSomeWork = false; // This outer loop re-runs if performing sync work on a root spawns
6083-
// additional sync work. If it happens too many times, it's very likely
6084-
// caused by some sort of infinite update loop. We already have a loop guard
6085-
// in place that will trigger an error on the n+1th update, but it's
6086-
// possible for that error to get swallowed if the setState is called from
6087-
// an unexpected place, like during the render phase. So as an added
6088-
// precaution, we also use a guard here.
6089-
//
6090-
// Ideally, there should be no known way to trigger this synchronous loop.
6091-
// It's really just here as a safety net.
6092-
//
6093-
// This limit is slightly larger than the one that throws inside setState,
6094-
// because that one is preferable because it includes a componens stack.
6095-
6096-
if (++nestedUpdatePasses > 60) {
6097-
// This is a fatal error, so we'll unschedule all the roots.
6098-
unscheduleAllRoots(); // TODO: Change this error message to something different to distinguish
6099-
// it from the one that is thrown from setState. Those are less fatal
6100-
// because they usually will result in the bad component being unmounted,
6101-
// and an error boundary being triggered, rather than us having to
6102-
// forcibly stop the entire scheduler.
6103-
6104-
var infiniteUpdateError = new Error(
6105-
"Maximum update depth exceeded. This can happen when a component " +
6106-
"repeatedly calls setState inside componentWillUpdate or " +
6107-
"componentDidUpdate. React limits the number of nested updates to " +
6108-
"prevent infinite loops."
6109-
);
6110-
6111-
if (errors === null) {
6112-
errors = [infiniteUpdateError];
6113-
} else {
6114-
errors.push(infiniteUpdateError);
6115-
}
6116-
6117-
break;
6118-
}
6119-
6066+
didPerformSomeWork = false;
61206067
var root = firstScheduledRoot;
61216068

61226069
while (root !== null) {
@@ -20018,13 +19965,7 @@ var workInProgressRootPingedLanes = NoLanes; // Errors that are thrown during th
2001819965
var workInProgressRootConcurrentErrors = null; // These are errors that we recovered from without surfacing them to the UI.
2001919966
// We will log them once the tree commits.
2002019967

20021-
var workInProgressRootRecoverableErrors = null; // Tracks when an update occurs during the render phase.
20022-
20023-
var workInProgressRootDidIncludeRecursiveRenderUpdate = false; // Thacks when an update occurs during the commit phase. It's a separate
20024-
// variable from the one for renders because the commit phase may run
20025-
// concurrently to a render phase.
20026-
20027-
var didIncludeCommitPhaseUpdate = false; // The most recent time we either committed a fallback, or when a fallback was
19968+
var workInProgressRootRecoverableErrors = null; // The most recent time we either committed a fallback, or when a fallback was
2002819969
// filled in with the resolved UI. This lets us throttle the appearance of new
2002919970
// content as it streams in, to minimize jank.
2003019971
// TODO: Think of a better name for this variable?
@@ -20506,8 +20447,7 @@ function finishConcurrentRender(root, exitStatus, finishedWork, lanes) {
2050620447
commitRoot(
2050720448
root,
2050820449
workInProgressRootRecoverableErrors,
20509-
workInProgressTransitions,
20510-
workInProgressRootDidIncludeRecursiveRenderUpdate
20450+
workInProgressTransitions
2051120451
);
2051220452
} else {
2051320453
if (includesOnlyRetries(lanes) && alwaysThrottleRetries) {
@@ -20537,7 +20477,6 @@ function finishConcurrentRender(root, exitStatus, finishedWork, lanes) {
2053720477
finishedWork,
2053820478
workInProgressRootRecoverableErrors,
2053920479
workInProgressTransitions,
20540-
workInProgressRootDidIncludeRecursiveRenderUpdate,
2054120480
lanes
2054220481
),
2054320482
msUntilTimeout
@@ -20551,7 +20490,6 @@ function finishConcurrentRender(root, exitStatus, finishedWork, lanes) {
2055120490
finishedWork,
2055220491
workInProgressRootRecoverableErrors,
2055320492
workInProgressTransitions,
20554-
workInProgressRootDidIncludeRecursiveRenderUpdate,
2055520493
lanes
2055620494
);
2055720495
}
@@ -20562,7 +20500,6 @@ function commitRootWhenReady(
2056220500
finishedWork,
2056320501
recoverableErrors,
2056420502
transitions,
20565-
didIncludeRenderPhaseUpdate,
2056620503
lanes
2056720504
) {
2056820505
// TODO: Combine retry throttling with Suspensey commits. Right now they run
@@ -20586,20 +20523,14 @@ function commitRootWhenReady(
2058620523
// us that it's ready. This will be canceled if we start work on the
2058720524
// root again.
2058820525
root.cancelPendingCommit = schedulePendingCommit(
20589-
commitRoot.bind(
20590-
null,
20591-
root,
20592-
recoverableErrors,
20593-
transitions,
20594-
didIncludeRenderPhaseUpdate
20595-
)
20526+
commitRoot.bind(null, root, recoverableErrors, transitions)
2059620527
);
2059720528
markRootSuspended(root, lanes);
2059820529
return;
2059920530
}
2060020531
} // Otherwise, commit immediately.
2060120532

20602-
commitRoot(root, recoverableErrors, transitions, didIncludeRenderPhaseUpdate);
20533+
commitRoot(root, recoverableErrors, transitions);
2060320534
}
2060420535

2060520536
function isRenderConsistentWithExternalStores(finishedWork) {
@@ -20662,49 +20593,18 @@ function isRenderConsistentWithExternalStores(finishedWork) {
2066220593
// eslint-disable-next-line no-unreachable
2066320594

2066420595
return true;
20665-
} // The extra indirections around markRootUpdated and markRootSuspended is
20666-
// needed to avoid a circular dependency between this module and
20667-
// ReactFiberLane. There's probably a better way to split up these modules and
20668-
// avoid this problem. Perhaps all the root-marking functions should move into
20669-
// the work loop.
20670-
20671-
function markRootUpdated(root, updatedLanes) {
20672-
markRootUpdated$1(root, updatedLanes); // Check for recursive updates
20673-
20674-
if (executionContext & RenderContext) {
20675-
workInProgressRootDidIncludeRecursiveRenderUpdate = true;
20676-
} else if (executionContext & CommitContext) {
20677-
didIncludeCommitPhaseUpdate = true;
20678-
}
20679-
20680-
throwIfInfiniteUpdateLoopDetected();
20681-
}
20682-
20683-
function markRootPinged(root, pingedLanes) {
20684-
markRootPinged$1(root, pingedLanes); // Check for recursive pings. Pings are conceptually different from updates in
20685-
// other contexts but we call it an "update" in this context because
20686-
// repeatedly pinging a suspended render can cause a recursive render loop.
20687-
// The relevant property is that it can result in a new render attempt
20688-
// being scheduled.
20689-
20690-
if (executionContext & RenderContext) {
20691-
workInProgressRootDidIncludeRecursiveRenderUpdate = true;
20692-
} else if (executionContext & CommitContext) {
20693-
didIncludeCommitPhaseUpdate = true;
20694-
}
20695-
20696-
throwIfInfiniteUpdateLoopDetected();
2069720596
}
2069820597

2069920598
function markRootSuspended(root, suspendedLanes) {
2070020599
// When suspending, we should always exclude lanes that were pinged or (more
2070120600
// rarely, since we try to avoid it) updated during the render phase.
20601+
// TODO: Lol maybe there's a better way to factor this besides this
20602+
// obnoxiously named function :)
2070220603
suspendedLanes = removeLanes(suspendedLanes, workInProgressRootPingedLanes);
2070320604
suspendedLanes = removeLanes(
2070420605
suspendedLanes,
2070520606
workInProgressRootInterleavedUpdatedLanes
2070620607
);
20707-
2070820608
markRootSuspended$1(root, suspendedLanes);
2070920609
} // This is the entry point for synchronous tasks that don't go
2071020610
// through Scheduler
@@ -20775,8 +20675,7 @@ function performSyncWorkOnRoot(root) {
2077520675
commitRoot(
2077620676
root,
2077720677
workInProgressRootRecoverableErrors,
20778-
workInProgressTransitions,
20779-
workInProgressRootDidIncludeRecursiveRenderUpdate
20678+
workInProgressTransitions
2078020679
); // Before exiting, make sure there's a callback scheduled for the next
2078120680
// pending level.
2078220681

@@ -20917,7 +20816,6 @@ function prepareFreshStack(root, lanes) {
2091720816
workInProgressRootPingedLanes = NoLanes;
2091820817
workInProgressRootConcurrentErrors = null;
2091920818
workInProgressRootRecoverableErrors = null;
20920-
workInProgressRootDidIncludeRecursiveRenderUpdate = false;
2092120819
finishQueueingConcurrentUpdates();
2092220820

2092320821
{
@@ -21832,12 +21730,7 @@ function unwindUnitOfWork(unitOfWork) {
2183221730
workInProgress = null;
2183321731
}
2183421732

21835-
function commitRoot(
21836-
root,
21837-
recoverableErrors,
21838-
transitions,
21839-
didIncludeRenderPhaseUpdate
21840-
) {
21733+
function commitRoot(root, recoverableErrors, transitions) {
2184121734
// TODO: This no longer makes any sense. We already wrap the mutation and
2184221735
// layout phases. Should be able to remove.
2184321736
var previousUpdateLanePriority = getCurrentUpdatePriority();
@@ -21850,7 +21743,6 @@ function commitRoot(
2185021743
root,
2185121744
recoverableErrors,
2185221745
transitions,
21853-
didIncludeRenderPhaseUpdate,
2185421746
previousUpdateLanePriority
2185521747
);
2185621748
} finally {
@@ -21865,7 +21757,6 @@ function commitRootImpl(
2186521757
root,
2186621758
recoverableErrors,
2186721759
transitions,
21868-
didIncludeRenderPhaseUpdate,
2186921760
renderPriorityLevel
2187021761
) {
2187121762
do {
@@ -21921,9 +21812,7 @@ function commitRootImpl(
2192121812

2192221813
var concurrentlyUpdatedLanes = getConcurrentlyUpdatedLanes();
2192321814
remainingLanes = mergeLanes(remainingLanes, concurrentlyUpdatedLanes);
21924-
markRootFinished(root, remainingLanes); // Reset this before firing side effects so we can detect recursive updates.
21925-
21926-
didIncludeCommitPhaseUpdate = false;
21815+
markRootFinished(root, remainingLanes);
2192721816

2192821817
if (root === workInProgressRoot) {
2192921818
// We can reset these now that they are finished.
@@ -22104,18 +21993,7 @@ function commitRootImpl(
2210421993

2210521994
remainingLanes = root.pendingLanes;
2210621995

22107-
if (
22108-
// Check if there was a recursive update spawned by this render, in either
22109-
// the render phase or the commit phase. We track these explicitly because
22110-
// we can't infer from the remaining lanes alone.
22111-
didIncludeCommitPhaseUpdate ||
22112-
didIncludeRenderPhaseUpdate || // As an additional precaution, we also check if there's any remaining sync
22113-
// work. Theoretically this should be unreachable but if there's a mistake
22114-
// in React it helps to be overly defensive given how hard it is to debug
22115-
// those scenarios otherwise. This won't catch recursive async updates,
22116-
// though, which is why we check the flags above first.
22117-
includesSyncLane(remainingLanes)
22118-
) {
21996+
if (includesSyncLane(remainingLanes)) {
2211921997
{
2212021998
markNestedUpdateScheduled();
2212121999
} // Count the number of times the root synchronously re-renders without
@@ -22553,18 +22431,6 @@ function throwIfInfiniteUpdateLoopDetected() {
2255322431
nestedPassiveUpdateCount = 0;
2255422432
rootWithNestedUpdates = null;
2255522433
rootWithPassiveNestedUpdates = null;
22556-
22557-
if (executionContext & RenderContext && workInProgressRoot !== null) {
22558-
// We're in the render phase. Disable the concurrent error recovery
22559-
// mechanism to ensure that the error we're about to throw gets handled.
22560-
// We need it to trigger the nearest error boundary so that the infinite
22561-
// update loop is broken.
22562-
workInProgressRoot.errorRecoveryDisabledLanes = mergeLanes(
22563-
workInProgressRoot.errorRecoveryDisabledLanes,
22564-
workInProgressRootRenderLanes
22565-
);
22566-
}
22567-
2256822434
throw new Error(
2256922435
"Maximum update depth exceeded. This can happen when a component " +
2257022436
"repeatedly calls setState inside componentWillUpdate or " +
@@ -24037,7 +23903,7 @@ function createFiberRoot(
2403723903
return root;
2403823904
}
2403923905

24040-
var ReactVersion = "18.3.0-canary-fc801116c-20230629";
23906+
var ReactVersion = "18.3.0-canary-7f362de15-20230630";
2404123907

2404223908
// Might add PROFILE later.
2404323909

0 commit comments

Comments
 (0)