@@ -20823,10 +20823,10 @@ function renderRootSync(root, lanes) {
20823
20823
}
20824
20824
20825
20825
default: {
20826
- // Continue with the normal work loop.
20826
+ // Unwind then continue with the normal work loop.
20827
20827
workInProgressSuspendedReason = NotSuspended;
20828
20828
workInProgressThrownValue = null;
20829
- unwindSuspendedUnitOfWork (unitOfWork, thrownValue);
20829
+ throwAndUnwindWorkLoop (unitOfWork, thrownValue);
20830
20830
break;
20831
20831
}
20832
20832
}
@@ -20897,7 +20897,7 @@ function renderRootConcurrent(root, lanes) {
20897
20897
// Unwind then continue with the normal work loop.
20898
20898
workInProgressSuspendedReason = NotSuspended;
20899
20899
workInProgressThrownValue = null;
20900
- unwindSuspendedUnitOfWork (unitOfWork, thrownValue);
20900
+ throwAndUnwindWorkLoop (unitOfWork, thrownValue);
20901
20901
break;
20902
20902
}
20903
20903
@@ -20962,7 +20962,7 @@ function renderRootConcurrent(root, lanes) {
20962
20962
// Otherwise, unwind then continue with the normal work loop.
20963
20963
workInProgressSuspendedReason = NotSuspended;
20964
20964
workInProgressThrownValue = null;
20965
- unwindSuspendedUnitOfWork (unitOfWork, thrownValue);
20965
+ throwAndUnwindWorkLoop (unitOfWork, thrownValue);
20966
20966
}
20967
20967
20968
20968
break;
@@ -21027,7 +21027,7 @@ function renderRootConcurrent(root, lanes) {
21027
21027
21028
21028
workInProgressSuspendedReason = NotSuspended;
21029
21029
workInProgressThrownValue = null;
21030
- unwindSuspendedUnitOfWork (unitOfWork, thrownValue);
21030
+ throwAndUnwindWorkLoop (unitOfWork, thrownValue);
21031
21031
break;
21032
21032
}
21033
21033
@@ -21038,7 +21038,7 @@ function renderRootConcurrent(root, lanes) {
21038
21038
// always unwind.
21039
21039
workInProgressSuspendedReason = NotSuspended;
21040
21040
workInProgressThrownValue = null;
21041
- unwindSuspendedUnitOfWork (unitOfWork, thrownValue);
21041
+ throwAndUnwindWorkLoop (unitOfWork, thrownValue);
21042
21042
break;
21043
21043
}
21044
21044
@@ -21225,7 +21225,7 @@ function replaySuspendedUnitOfWork(unitOfWork) {
21225
21225
ReactCurrentOwner.current = null;
21226
21226
}
21227
21227
21228
- function unwindSuspendedUnitOfWork (unitOfWork, thrownValue) {
21228
+ function throwAndUnwindWorkLoop (unitOfWork, thrownValue) {
21229
21229
// This is a fork of performUnitOfWork specifcally for unwinding a fiber
21230
21230
// that threw an exception.
21231
21231
//
@@ -21268,9 +21268,23 @@ function unwindSuspendedUnitOfWork(unitOfWork, thrownValue) {
21268
21268
// To prevent an infinite loop, bubble the error up to the next parent.
21269
21269
workInProgress = returnFiber;
21270
21270
throw error;
21271
- } // Return to the normal work loop.
21271
+ }
21272
21272
21273
- completeUnitOfWork(unitOfWork);
21273
+ if (unitOfWork.flags & Incomplete) {
21274
+ // Unwind the stack until we reach the nearest boundary.
21275
+ unwindUnitOfWork(unitOfWork);
21276
+ } else {
21277
+ // Although the fiber suspended, we're intentionally going to commit it in
21278
+ // an inconsistent state. We can do this safely in cases where we know the
21279
+ // inconsistent tree will be hidden.
21280
+ //
21281
+ // This currently only applies to Legacy Suspense implementation, but we may
21282
+ // port a version of this to concurrent roots, too, when performing a
21283
+ // synchronous render. Because that will allow us to mutate the tree as we
21284
+ // go instead of buffering mutations until the end. Though it's unclear if
21285
+ // this particular path is how that would be implemented.
21286
+ completeUnitOfWork(unitOfWork);
21287
+ }
21274
21288
}
21275
21289
21276
21290
function completeUnitOfWork(unitOfWork) {
@@ -21279,75 +21293,41 @@ function completeUnitOfWork(unitOfWork) {
21279
21293
var completedWork = unitOfWork;
21280
21294
21281
21295
do {
21282
- // The current, flushed, state of this fiber is the alternate. Ideally
21296
+ {
21297
+ {
21298
+ if ((completedWork.flags & Incomplete) !== NoFlags$1) {
21299
+ // NOTE: If we re-enable sibling prerendering in some cases, this branch
21300
+ // is where we would switch to the unwinding path.
21301
+ error(
21302
+ "Internal React error: Expected this fiber to be complete, but " +
21303
+ "it isn't. It should have been unwound. This is a bug in React."
21304
+ );
21305
+ }
21306
+ }
21307
+ } // The current, flushed, state of this fiber is the alternate. Ideally
21283
21308
// nothing should rely on this, but relying on it here means that we don't
21284
21309
// need an additional field on the work in progress.
21285
- var current = completedWork.alternate;
21286
- var returnFiber = completedWork.return; // Check if the work completed or if something threw.
21287
21310
21288
- if ((completedWork.flags & Incomplete) === NoFlags$1) {
21289
- setCurrentFiber(completedWork);
21290
- var next = void 0;
21291
-
21292
- if ((completedWork.mode & ProfileMode) === NoMode) {
21293
- next = completeWork(current, completedWork, renderLanes);
21294
- } else {
21295
- startProfilerTimer(completedWork);
21296
- next = completeWork(current, completedWork, renderLanes); // Update render duration assuming we didn't error.
21297
-
21298
- stopProfilerTimerIfRunningAndRecordDelta(completedWork, false);
21299
- }
21300
-
21301
- resetCurrentFiber();
21311
+ var current = completedWork.alternate;
21312
+ var returnFiber = completedWork.return;
21313
+ setCurrentFiber(completedWork);
21314
+ var next = void 0;
21302
21315
21303
- if (next !== null) {
21304
- // Completing this fiber spawned new work. Work on that next.
21305
- workInProgress = next;
21306
- return;
21307
- }
21316
+ if ((completedWork.mode & ProfileMode) === NoMode) {
21317
+ next = completeWork(current, completedWork, renderLanes);
21308
21318
} else {
21309
- // This fiber did not complete because something threw. Pop values off
21310
- // the stack without entering the complete phase. If this is a boundary,
21311
- // capture values if possible.
21312
- var _next = unwindWork(current, completedWork); // Because this fiber did not complete, don't reset its lanes.
21313
-
21314
- if (_next !== null) {
21315
- // If completing this work spawned new work, do that next. We'll come
21316
- // back here again.
21317
- // Since we're restarting, remove anything that is not a host effect
21318
- // from the effect tag.
21319
- _next.flags &= HostEffectMask;
21320
- workInProgress = _next;
21321
- return;
21322
- }
21319
+ startProfilerTimer(completedWork);
21320
+ next = completeWork(current, completedWork, renderLanes); // Update render duration assuming we didn't error.
21323
21321
21324
- if ((completedWork.mode & ProfileMode) !== NoMode) {
21325
- // Record the render duration for the fiber that errored.
21326
- stopProfilerTimerIfRunningAndRecordDelta(completedWork, false); // Include the time spent working on failed children before continuing.
21327
-
21328
- var actualDuration = completedWork.actualDuration;
21329
- var child = completedWork.child;
21330
-
21331
- while (child !== null) {
21332
- // $FlowFixMe[unsafe-addition] addition with possible null/undefined value
21333
- actualDuration += child.actualDuration;
21334
- child = child.sibling;
21335
- }
21322
+ stopProfilerTimerIfRunningAndRecordDelta(completedWork, false);
21323
+ }
21336
21324
21337
- completedWork.actualDuration = actualDuration;
21338
- }
21325
+ resetCurrentFiber();
21339
21326
21340
- if (returnFiber !== null) {
21341
- // Mark the parent fiber as incomplete and clear its subtree flags.
21342
- returnFiber.flags |= Incomplete;
21343
- returnFiber.subtreeFlags = NoFlags$1;
21344
- returnFiber.deletions = null;
21345
- } else {
21346
- // We've unwound all the way to the root.
21347
- workInProgressRootExitStatus = RootDidNotComplete;
21348
- workInProgress = null;
21349
- return;
21350
- }
21327
+ if (next !== null) {
21328
+ // Completing this fiber spawned new work. Work on that next.
21329
+ workInProgress = next;
21330
+ return;
21351
21331
}
21352
21332
21353
21333
var siblingFiber = completedWork.sibling;
@@ -21369,6 +21349,70 @@ function completeUnitOfWork(unitOfWork) {
21369
21349
}
21370
21350
}
21371
21351
21352
+ function unwindUnitOfWork(unitOfWork) {
21353
+ var incompleteWork = unitOfWork;
21354
+
21355
+ do {
21356
+ // The current, flushed, state of this fiber is the alternate. Ideally
21357
+ // nothing should rely on this, but relying on it here means that we don't
21358
+ // need an additional field on the work in progress.
21359
+ var current = incompleteWork.alternate; // This fiber did not complete because something threw. Pop values off
21360
+ // the stack without entering the complete phase. If this is a boundary,
21361
+ // capture values if possible.
21362
+
21363
+ var next = unwindWork(current, incompleteWork); // Because this fiber did not complete, don't reset its lanes.
21364
+
21365
+ if (next !== null) {
21366
+ // Found a boundary that can handle this exception. Re-renter the
21367
+ // begin phase. This branch will return us to the normal work loop.
21368
+ //
21369
+ // Since we're restarting, remove anything that is not a host effect
21370
+ // from the effect tag.
21371
+ next.flags &= HostEffectMask;
21372
+ workInProgress = next;
21373
+ return;
21374
+ } // Keep unwinding until we reach either a boundary or the root.
21375
+
21376
+ if ((incompleteWork.mode & ProfileMode) !== NoMode) {
21377
+ // Record the render duration for the fiber that errored.
21378
+ stopProfilerTimerIfRunningAndRecordDelta(incompleteWork, false); // Include the time spent working on failed children before continuing.
21379
+
21380
+ var actualDuration = incompleteWork.actualDuration;
21381
+ var child = incompleteWork.child;
21382
+
21383
+ while (child !== null) {
21384
+ // $FlowFixMe[unsafe-addition] addition with possible null/undefined value
21385
+ actualDuration += child.actualDuration;
21386
+ child = child.sibling;
21387
+ }
21388
+
21389
+ incompleteWork.actualDuration = actualDuration;
21390
+ } // TODO: Once we stop prerendering siblings, instead of resetting the parent
21391
+ // of the node being unwound, we should be able to reset node itself as we
21392
+ // unwind the stack. Saves an additional null check.
21393
+
21394
+ var returnFiber = incompleteWork.return;
21395
+
21396
+ if (returnFiber !== null) {
21397
+ // Mark the parent fiber as incomplete and clear its subtree flags.
21398
+ // TODO: Once we stop prerendering siblings, we may be able to get rid of
21399
+ // the Incomplete flag because unwinding to the nearest boundary will
21400
+ // happen synchronously.
21401
+ returnFiber.flags |= Incomplete;
21402
+ returnFiber.subtreeFlags = NoFlags$1;
21403
+ returnFiber.deletions = null;
21404
+ }
21405
+ // $FlowFixMe[incompatible-type] we bail out when we get a null
21406
+
21407
+ incompleteWork = returnFiber; // Update the next thing we're working on in case something throws.
21408
+
21409
+ workInProgress = incompleteWork;
21410
+ } while (incompleteWork !== null); // We've unwound all the way to the root.
21411
+
21412
+ workInProgressRootExitStatus = RootDidNotComplete;
21413
+ workInProgress = null;
21414
+ }
21415
+
21372
21416
function commitRoot(root, recoverableErrors, transitions) {
21373
21417
// TODO: This no longer makes any sense. We already wrap the mutation and
21374
21418
// layout phases. Should be able to remove.
@@ -23588,7 +23632,7 @@ function createFiberRoot(
23588
23632
return root;
23589
23633
}
23590
23634
23591
- var ReactVersion = "18.3.0-next-77ba1618a-20230320 ";
23635
+ var ReactVersion = "18.3.0-next-0018cf224-20230321 ";
23592
23636
23593
23637
// Might add PROFILE later.
23594
23638
0 commit comments