@samitouri / QOS-React-1 / commits / 2c959f1d77

[Fiber] Track debugInfo on module state instead of stack (#29807)

Stacked on #29804. Transferring of debugInfo was added in #28286. It represents the parent stack between the current Fiber and into the next Fiber we're about to create. I.e. Server Components in between. ~I don't love passing DEV-only fields as arguments anyway since I don't trust closure to remove unused arguments that way.~ EDIT: Actually it seems like closure handled that just fine before which is why this is no change in prod. Instead, I track it on the module scope. Notably with DON'T use try/finally because if something throws we want to observe what it was at the time we threw. Like the pattern we use many other places. Now we can use this when we create the Throw Fiber to associate the Server Components that were part of the parent stack before this error threw. There by giving us the correct parent stacks at the location that threw.

Sebastian Markbåge committed Jun 11, 2024 at 17:04 UTC 2c959f1d775e9c216d029d198971d06a1f8c892a
2 files changed +126 -124
packages/react-client/src/__tests__/ReactFlight-test.js
+4 -2
@@ -1050,8 +1050,10 @@ describe('ReactFlight', () => {
1050 }
1051
1052 const expectedStack = __DEV__
1053 - ? // TODO: This should include Throw but it doesn't have a Fiber.
1054 - '\n in div' + '\n in ErrorBoundary (at **)' + '\n in App'
1053 + ? '\n in Throw' +
1054 + '\n in div' +
1055 + '\n in ErrorBoundary (at **)' +
1056 + '\n in App'
1057 : '\n in div' + '\n in ErrorBoundary (at **)';
1058
1059 function App() {
packages/react-reconciler/src/ReactChildFiber.js
+122 -122
@@ -76,23 +76,27 @@ import {runWithFiberInDEV} from './ReactCurrentFiber';
76 let thenableState: ThenableState | null = null;
77 let thenableIndexCounter: number = 0;
78
79 -function mergeDebugInfo(
80 - outer: ReactDebugInfo | null,
81 - inner: ReactDebugInfo | null | void,
82 -): ReactDebugInfo | null {
79 +// Server Components Meta Data
80 +let currentDebugInfo: null | ReactDebugInfo = null;
81 +
82 +function pushDebugInfo(
83 + debugInfo: null | ReactDebugInfo,
84 +): null | ReactDebugInfo {
85 if (!__DEV__) {
86 return null;
87 }
86 - if (inner == null) {
87 - return outer;
88 - } else if (outer === null) {
89 - return inner;
88 + const previousDebugInfo = currentDebugInfo;
89 + if (debugInfo == null) {
90 + // Leave inplace
91 + } else if (previousDebugInfo === null) {
92 + currentDebugInfo = debugInfo;
93 } else {
94 // If we have two debugInfo, we need to create a new one. This makes the array no longer
95 // live so we'll miss any future updates if we received more so ideally we should always
96 // do this after both have fully resolved/unsuspended.
94 - return outer.concat(inner);
97 + currentDebugInfo = previousDebugInfo.concat(debugInfo);
98 }
99 + return previousDebugInfo;
100 }
101
102 let didWarnAboutMaps;
@@ -497,14 +501,13 @@ function createChildReconciler(
501 current: Fiber | null,
502 textContent: string,
503 lanes: Lanes,
500 - debugInfo: ReactDebugInfo | null,
504 ) {
505 if (current === null || current.tag !== HostText) {
506 // Insert
507 const created = createFiberFromText(textContent, returnFiber.mode, lanes);
508 created.return = returnFiber;
509 if (__DEV__) {
507 - created._debugInfo = debugInfo;
510 + created._debugInfo = currentDebugInfo;
511 }
512 return created;
513 } else {
@@ -512,7 +515,7 @@ function createChildReconciler(
515 const existing = useFiber(current, textContent);
516 existing.return = returnFiber;
517 if (__DEV__) {
515 - existing._debugInfo = debugInfo;
518 + existing._debugInfo = currentDebugInfo;
519 }
520 return existing;
521 }
@@ -523,7 +526,6 @@ function createChildReconciler(
526 current: Fiber | null,
527 element: ReactElement,
528 lanes: Lanes,
526 - debugInfo: ReactDebugInfo | null,
529 ): Fiber {
530 const elementType = element.type;
531 if (elementType === REACT_FRAGMENT_TYPE) {
@@ -533,7 +535,6 @@ function createChildReconciler(
535 element.props.children,
536 lanes,
537 element.key,
536 - debugInfo,
538 );
539 validateFragmentProps(element, updated, returnFiber);
540 return updated;
@@ -560,7 +561,7 @@ function createChildReconciler(
561 existing.return = returnFiber;
562 if (__DEV__) {
563 existing._debugOwner = element._owner;
563 - existing._debugInfo = debugInfo;
564 + existing._debugInfo = currentDebugInfo;
565 }
566 return existing;
567 }
@@ -570,7 +571,7 @@ function createChildReconciler(
571 coerceRef(returnFiber, current, created, element);
572 created.return = returnFiber;
573 if (__DEV__) {
573 - created._debugInfo = debugInfo;
574 + created._debugInfo = currentDebugInfo;
575 }
576 return created;
577 }
@@ -580,7 +581,6 @@ function createChildReconciler(
581 current: Fiber | null,
582 portal: ReactPortal,
583 lanes: Lanes,
583 - debugInfo: ReactDebugInfo | null,
584 ): Fiber {
585 if (
586 current === null ||
@@ -592,7 +592,7 @@ function createChildReconciler(
592 const created = createFiberFromPortal(portal, returnFiber.mode, lanes);
593 created.return = returnFiber;
594 if (__DEV__) {
595 - created._debugInfo = debugInfo;
595 + created._debugInfo = currentDebugInfo;
596 }
597 return created;
598 } else {
@@ -600,7 +600,7 @@ function createChildReconciler(
600 const existing = useFiber(current, portal.children || []);
601 existing.return = returnFiber;
602 if (__DEV__) {
603 - existing._debugInfo = debugInfo;
603 + existing._debugInfo = currentDebugInfo;
604 }
605 return existing;
606 }
@@ -612,7 +612,6 @@ function createChildReconciler(
612 fragment: Iterable<React$Node>,
613 lanes: Lanes,
614 key: null | string,
615 - debugInfo: null | ReactDebugInfo,
615 ): Fiber {
616 if (current === null || current.tag !== Fragment) {
617 // Insert
@@ -624,7 +623,7 @@ function createChildReconciler(
623 );
624 created.return = returnFiber;
625 if (__DEV__) {
627 - created._debugInfo = debugInfo;
626 + created._debugInfo = currentDebugInfo;
627 }
628 return created;
629 } else {
@@ -632,7 +631,7 @@ function createChildReconciler(
631 const existing = useFiber(current, fragment);
632 existing.return = returnFiber;
633 if (__DEV__) {
635 - existing._debugInfo = debugInfo;
634 + existing._debugInfo = currentDebugInfo;
635 }
636 return existing;
637 }
@@ -642,7 +641,6 @@ function createChildReconciler(
641 returnFiber: Fiber,
642 newChild: any,
643 lanes: Lanes,
645 - debugInfo: ReactDebugInfo | null,
644 ): Fiber | null {
645 if (
646 (typeof newChild === 'string' && newChild !== '') ||
@@ -660,7 +658,7 @@ function createChildReconciler(
658 );
659 created.return = returnFiber;
660 if (__DEV__) {
663 - created._debugInfo = debugInfo;
661 + created._debugInfo = currentDebugInfo;
662 }
663 return created;
664 }
@@ -676,7 +674,9 @@ function createChildReconciler(
674 coerceRef(returnFiber, null, created, newChild);
675 created.return = returnFiber;
676 if (__DEV__) {
679 - created._debugInfo = mergeDebugInfo(debugInfo, newChild._debugInfo);
677 + const prevDebugInfo = pushDebugInfo(newChild._debugInfo);
678 + created._debugInfo = currentDebugInfo;
679 + currentDebugInfo = prevDebugInfo;
680 }
681 return created;
682 }
@@ -688,11 +688,12 @@ function createChildReconciler(
688 );
689 created.return = returnFiber;
690 if (__DEV__) {
691 - created._debugInfo = debugInfo;
691 + created._debugInfo = currentDebugInfo;
692 }
693 return created;
694 }
695 case REACT_LAZY_TYPE: {
696 + const prevDebugInfo = pushDebugInfo(newChild._debugInfo);
697 let resolvedChild;
698 if (__DEV__) {
699 resolvedChild = callLazyInitInDEV(newChild);
@@ -701,12 +702,9 @@ function createChildReconciler(
702 const init = newChild._init;
703 resolvedChild = init(payload);
704 }
704 - return createChild(
705 - returnFiber,
706 - resolvedChild,
707 - lanes,
708 - mergeDebugInfo(debugInfo, newChild._debugInfo), // call merge after init
709 - );
705 + const created = createChild(returnFiber, resolvedChild, lanes);
706 + currentDebugInfo = prevDebugInfo;
707 + return created;
708 }
709 }
710
@@ -724,7 +722,9 @@ function createChildReconciler(
722 );
723 created.return = returnFiber;
724 if (__DEV__) {
727 - created._debugInfo = mergeDebugInfo(debugInfo, newChild._debugInfo);
725 + const prevDebugInfo = pushDebugInfo(newChild._debugInfo);
726 + created._debugInfo = currentDebugInfo;
727 + currentDebugInfo = prevDebugInfo;
728 }
729 return created;
730 }
@@ -734,12 +734,14 @@ function createChildReconciler(
734 // Unwrap the inner value and recursively call this function again.
735 if (typeof newChild.then === 'function') {
736 const thenable: Thenable<any> = (newChild: any);
737 - return createChild(
737 + const prevDebugInfo = pushDebugInfo(newChild._debugInfo);
738 + const created = createChild(
739 returnFiber,
740 unwrapThenable(thenable),
741 lanes,
741 - mergeDebugInfo(debugInfo, newChild._debugInfo),
742 );
743 + currentDebugInfo = prevDebugInfo;
744 + return created;
745 }
746
747 if (newChild.$$typeof === REACT_CONTEXT_TYPE) {
@@ -748,7 +750,6 @@ function createChildReconciler(
750 returnFiber,
751 readContextDuringReconciliation(returnFiber, context, lanes),
752 lanes,
751 - debugInfo,
753 );
754 }
755
@@ -772,7 +773,6 @@ function createChildReconciler(
773 oldFiber: Fiber | null,
774 newChild: any,
775 lanes: Lanes,
775 - debugInfo: null | ReactDebugInfo,
776 ): Fiber | null {
777 // Update the fiber if the keys match, otherwise return null.
778 const key = oldFiber !== null ? oldFiber.key : null;
@@ -794,7 +794,6 @@ function createChildReconciler(
794 // $FlowFixMe[unsafe-addition] Flow doesn't want us to use `+` operator with string and bigint
795 '' + newChild,
796 lanes,
797 - debugInfo,
797 );
798 }
799
@@ -802,31 +801,28 @@ function createChildReconciler(
801 switch (newChild.$$typeof) {
802 case REACT_ELEMENT_TYPE: {
803 if (newChild.key === key) {
805 - return updateElement(
804 + const prevDebugInfo = pushDebugInfo(newChild._debugInfo);
805 + const updated = updateElement(
806 returnFiber,
807 oldFiber,
808 newChild,
809 lanes,
810 - mergeDebugInfo(debugInfo, newChild._debugInfo),
810 );
811 + currentDebugInfo = prevDebugInfo;
812 + return updated;
813 } else {
814 return null;
815 }
816 }
817 case REACT_PORTAL_TYPE: {
818 if (newChild.key === key) {
818 - return updatePortal(
819 - returnFiber,
820 - oldFiber,
821 - newChild,
822 - lanes,
823 - debugInfo,
824 - );
819 + return updatePortal(returnFiber, oldFiber, newChild, lanes);
820 } else {
821 return null;
822 }
823 }
824 case REACT_LAZY_TYPE: {
825 + const prevDebugInfo = pushDebugInfo(newChild._debugInfo);
826 let resolvedChild;
827 if (__DEV__) {
828 resolvedChild = callLazyInitInDEV(newChild);
@@ -835,13 +831,14 @@ function createChildReconciler(
831 const init = newChild._init;
832 resolvedChild = init(payload);
833 }
838 - return updateSlot(
834 + const updated = updateSlot(
835 returnFiber,
836 oldFiber,
837 resolvedChild,
838 lanes,
843 - mergeDebugInfo(debugInfo, newChild._debugInfo),
839 );
840 + currentDebugInfo = prevDebugInfo;
841 + return updated;
842 }
843 }
844
@@ -855,14 +852,16 @@ function createChildReconciler(
852 return null;
853 }
854
858 - return updateFragment(
855 + const prevDebugInfo = pushDebugInfo(newChild._debugInfo);
856 + const updated = updateFragment(
857 returnFiber,
858 oldFiber,
859 newChild,
860 lanes,
861 null,
864 - mergeDebugInfo(debugInfo, newChild._debugInfo),
862 );
863 + currentDebugInfo = prevDebugInfo;
864 + return updated;
865 }
866
867 // Usable node types
@@ -870,13 +869,15 @@ function createChildReconciler(
869 // Unwrap the inner value and recursively call this function again.
870 if (typeof newChild.then === 'function') {
871 const thenable: Thenable<any> = (newChild: any);
873 - return updateSlot(
872 + const prevDebugInfo = pushDebugInfo((thenable: any)._debugInfo);
873 + const updated = updateSlot(
874 returnFiber,
875 oldFiber,
876 unwrapThenable(thenable),
877 lanes,
878 - debugInfo,
878 );
879 + currentDebugInfo = prevDebugInfo;
880 + return updated;
881 }
882
883 if (newChild.$$typeof === REACT_CONTEXT_TYPE) {
@@ -886,7 +887,6 @@ function createChildReconciler(
887 oldFiber,
888 readContextDuringReconciliation(returnFiber, context, lanes),
889 lanes,
889 - debugInfo,
890 );
891 }
892
@@ -911,7 +911,6 @@ function createChildReconciler(
911 newIdx: number,
912 newChild: any,
913 lanes: Lanes,
914 - debugInfo: ReactDebugInfo | null,
914 ): Fiber | null {
915 if (
916 (typeof newChild === 'string' && newChild !== '') ||
@@ -927,7 +926,6 @@ function createChildReconciler(
926 // $FlowFixMe[unsafe-addition] Flow doesn't want us to use `+` operator with string and bigint
927 '' + newChild,
928 lanes,
930 - debugInfo,
929 );
930 }
931
@@ -938,28 +936,25 @@ function createChildReconciler(
936 existingChildren.get(
937 newChild.key === null ? newIdx : newChild.key,
938 ) || null;
941 - return updateElement(
939 + const prevDebugInfo = pushDebugInfo(newChild._debugInfo);
940 + const updated = updateElement(
941 returnFiber,
942 matchedFiber,
943 newChild,
944 lanes,
946 - mergeDebugInfo(debugInfo, newChild._debugInfo),
945 );
946 + currentDebugInfo = prevDebugInfo;
947 + return updated;
948 }
949 case REACT_PORTAL_TYPE: {
950 const matchedFiber =
951 existingChildren.get(
952 newChild.key === null ? newIdx : newChild.key,
953 ) || null;
954 - return updatePortal(
955 - returnFiber,
956 - matchedFiber,
957 - newChild,
958 - lanes,
959 - debugInfo,
960 - );
954 + return updatePortal(returnFiber, matchedFiber, newChild, lanes);
955 }
956 case REACT_LAZY_TYPE: {
957 + const prevDebugInfo = pushDebugInfo(newChild._debugInfo);
958 let resolvedChild;
959 if (__DEV__) {
960 resolvedChild = callLazyInitInDEV(newChild);
@@ -968,14 +963,15 @@ function createChildReconciler(
963 const init = newChild._init;
964 resolvedChild = init(payload);
965 }
971 - return updateFromMap(
966 + const updated = updateFromMap(
967 existingChildren,
968 returnFiber,
969 newIdx,
970 resolvedChild,
971 lanes,
977 - mergeDebugInfo(debugInfo, newChild._debugInfo),
972 );
973 + currentDebugInfo = prevDebugInfo;
974 + return updated;
975 }
976 }
977
@@ -986,14 +982,16 @@ function createChildReconciler(
982 typeof newChild[ASYNC_ITERATOR] === 'function')
983 ) {
984 const matchedFiber = existingChildren.get(newIdx) || null;
989 - return updateFragment(
985 + const prevDebugInfo = pushDebugInfo(newChild._debugInfo);
986 + const updated = updateFragment(
987 returnFiber,
988 matchedFiber,
989 newChild,
990 lanes,
991 null,
995 - mergeDebugInfo(debugInfo, newChild._debugInfo),
992 );
993 + currentDebugInfo = prevDebugInfo;
994 + return updated;
995 }
996
997 // Usable node types
@@ -1001,14 +999,16 @@ function createChildReconciler(
999 // Unwrap the inner value and recursively call this function again.
1000 if (typeof newChild.then === 'function') {
1001 const thenable: Thenable<any> = (newChild: any);
1004 - return updateFromMap(
1002 + const prevDebugInfo = pushDebugInfo((thenable: any)._debugInfo);
1003 + const updated = updateFromMap(
1004 existingChildren,
1005 returnFiber,
1006 newIdx,
1007 unwrapThenable(thenable),
1008 lanes,
1010 - debugInfo,
1009 );
1010 + currentDebugInfo = prevDebugInfo;
1011 + return updated;
1012 }
1013
1014 if (newChild.$$typeof === REACT_CONTEXT_TYPE) {
@@ -1019,7 +1019,6 @@ function createChildReconciler(
1019 newIdx,
1020 readContextDuringReconciliation(returnFiber, context, lanes),
1021 lanes,
1022 - debugInfo,
1022 );
1023 }
1024
@@ -1108,7 +1107,6 @@ function createChildReconciler(
1107 currentFirstChild: Fiber | null,
1108 newChildren: Array<any>,
1109 lanes: Lanes,
1111 - debugInfo: ReactDebugInfo | null,
1110 ): Fiber | null {
1111 // This algorithm can't optimize by searching from both ends since we
1112 // don't have backpointers on fibers. I'm trying to see how far we can get
@@ -1150,7 +1148,6 @@ function createChildReconciler(
1148 oldFiber,
1149 newChildren[newIdx],
1150 lanes,
1153 - debugInfo,
1151 );
1152 if (newFiber === null) {
1153 // TODO: This breaks on empty slots like null children. That's
@@ -1208,12 +1205,7 @@ function createChildReconciler(
1205 // If we don't have any more existing children we can choose a fast path
1206 // since the rest will all be insertions.
1207 for (; newIdx < newChildren.length; newIdx++) {
1211 - const newFiber = createChild(
1212 - returnFiber,
1213 - newChildren[newIdx],
1214 - lanes,
1215 - debugInfo,
1216 - );
1208 + const newFiber = createChild(returnFiber, newChildren[newIdx], lanes);
1209 if (newFiber === null) {
1210 continue;
1211 }
@@ -1252,7 +1244,6 @@ function createChildReconciler(
1244 newIdx,
1245 newChildren[newIdx],
1246 lanes,
1255 - debugInfo,
1247 );
1248 if (newFiber !== null) {
1249 if (__DEV__) {
@@ -1302,7 +1293,6 @@ function createChildReconciler(
1293 currentFirstChild: Fiber | null,
1294 newChildrenIterable: Iterable<mixed>,
1295 lanes: Lanes,
1305 - debugInfo: ReactDebugInfo | null,
1296 ): Fiber | null {
1297 // This is the same implementation as reconcileChildrenArray(),
1298 // but using the iterator instead.
@@ -1361,7 +1351,6 @@ function createChildReconciler(
1351 currentFirstChild,
1352 newChildren,
1353 lanes,
1364 - debugInfo,
1354 );
1355 }
1356
@@ -1370,7 +1359,6 @@ function createChildReconciler(
1359 currentFirstChild: Fiber | null,
1360 newChildrenIterable: AsyncIterable<mixed>,
1361 lanes: Lanes,
1373 - debugInfo: ReactDebugInfo | null,
1362 ): Fiber | null {
1363 const newChildren = newChildrenIterable[ASYNC_ITERATOR]();
1364
@@ -1419,7 +1407,6 @@ function createChildReconciler(
1407 currentFirstChild,
1408 iterator,
1409 lanes,
1422 - debugInfo,
1410 );
1411 }
1412
@@ -1428,7 +1415,6 @@ function createChildReconciler(
1415 currentFirstChild: Fiber | null,
1416 newChildren: ?Iterator<mixed>,
1417 lanes: Lanes,
1431 - debugInfo: ReactDebugInfo | null,
1418 ): Fiber | null {
1419 if (newChildren == null) {
1420 throw new Error('An iterable object provided no iterator.');
@@ -1456,13 +1442,7 @@ function createChildReconciler(
1442 } else {
1443 nextOldFiber = oldFiber.sibling;
1444 }
1459 - const newFiber = updateSlot(
1460 - returnFiber,
1461 - oldFiber,
1462 - step.value,
1463 - lanes,
1464 - debugInfo,
1465 - );
1445 + const newFiber = updateSlot(returnFiber, oldFiber, step.value, lanes);
1446 if (newFiber === null) {
1447 // TODO: This breaks on empty slots like null children. That's
1448 // unfortunate because it triggers the slow path all the time. We need
@@ -1519,7 +1499,7 @@ function createChildReconciler(
1499 // If we don't have any more existing children we can choose a fast path
1500 // since the rest will all be insertions.
1501 for (; !step.done; newIdx++, step = newChildren.next()) {
1522 - const newFiber = createChild(returnFiber, step.value, lanes, debugInfo);
1502 + const newFiber = createChild(returnFiber, step.value, lanes);
1503 if (newFiber === null) {
1504 continue;
1505 }
@@ -1558,7 +1538,6 @@ function createChildReconciler(
1538 newIdx,
1539 step.value,
1540 lanes,
1561 - debugInfo,
1541 );
1542 if (newFiber !== null) {
1543 if (__DEV__) {
@@ -1632,7 +1611,6 @@ function createChildReconciler(
1611 currentFirstChild: Fiber | null,
1612 element: ReactElement,
1613 lanes: Lanes,
1635 - debugInfo: ReactDebugInfo | null,
1614 ): Fiber {
1615 const key = element.key;
1616 let child = currentFirstChild;
@@ -1648,7 +1626,7 @@ function createChildReconciler(
1626 existing.return = returnFiber;
1627 if (__DEV__) {
1628 existing._debugOwner = element._owner;
1651 - existing._debugInfo = debugInfo;
1629 + existing._debugInfo = currentDebugInfo;
1630 }
1631 validateFragmentProps(element, existing, returnFiber);
1632 return existing;
@@ -1675,7 +1653,7 @@ function createChildReconciler(
1653 existing.return = returnFiber;
1654 if (__DEV__) {
1655 existing._debugOwner = element._owner;
1678 - existing._debugInfo = debugInfo;
1656 + existing._debugInfo = currentDebugInfo;
1657 }
1658 return existing;
1659 }
@@ -1698,7 +1676,7 @@ function createChildReconciler(
1676 );
1677 created.return = returnFiber;
1678 if (__DEV__) {
1701 - created._debugInfo = debugInfo;
1679 + created._debugInfo = currentDebugInfo;
1680 }
1681 validateFragmentProps(element, created, returnFiber);
1682 return created;
@@ -1707,7 +1685,7 @@ function createChildReconciler(
1685 coerceRef(returnFiber, currentFirstChild, created, element);
1686 created.return = returnFiber;
1687 if (__DEV__) {
1710 - created._debugInfo = debugInfo;
1688 + created._debugInfo = currentDebugInfo;
1689 }
1690 return created;
1691 }
@@ -1718,7 +1696,6 @@ function createChildReconciler(
1696 currentFirstChild: Fiber | null,
1697 portal: ReactPortal,
1698 lanes: Lanes,
1721 - debugInfo: ReactDebugInfo | null,
1699 ): Fiber {
1700 const key = portal.key;
1701 let child = currentFirstChild;
@@ -1758,7 +1735,6 @@ function createChildReconciler(
1735 currentFirstChild: Fiber | null,
1736 newChild: any,
1737 lanes: Lanes,
1761 - debugInfo: ReactDebugInfo | null,
1738 ): Fiber | null {
1739 // This function is only recursive for Usables/Lazy and not nested arrays.
1740 // That's so that using a Lazy wrapper is unobservable to the Fragment
@@ -1785,16 +1761,19 @@ function createChildReconciler(
1761 // Handle object types
1762 if (typeof newChild === 'object' && newChild !== null) {
1763 switch (newChild.$$typeof) {
1788 - case REACT_ELEMENT_TYPE:
1789 - return placeSingleChild(
1764 + case REACT_ELEMENT_TYPE: {
1765 + const prevDebugInfo = pushDebugInfo(newChild._debugInfo);
1766 + const firstChild = placeSingleChild(
1767 reconcileSingleElement(
1768 returnFiber,
1769 currentFirstChild,
1770 newChild,
1771 lanes,
1795 - mergeDebugInfo(debugInfo, newChild._debugInfo),
1772 ),
1773 );
1774 + currentDebugInfo = prevDebugInfo;
1775 + return firstChild;
1776 + }
1777 case REACT_PORTAL_TYPE:
1778 return placeSingleChild(
1779 reconcileSinglePortal(
@@ -1802,52 +1781,66 @@ function createChildReconciler(
1781 currentFirstChild,
1782 newChild,
1783 lanes,
1805 - debugInfo,
1784 ),
1785 );
1808 - case REACT_LAZY_TYPE:
1809 - const payload = newChild._payload;
1810 - const init = newChild._init;
1811 - return reconcileChildFibersImpl(
1786 + case REACT_LAZY_TYPE: {
1787 + const prevDebugInfo = pushDebugInfo(newChild._debugInfo);
1788 + let result;
1789 + if (__DEV__) {
1790 + result = callLazyInitInDEV(newChild);
1791 + } else {
1792 + const payload = newChild._payload;
1793 + const init = newChild._init;
1794 + result = init(payload);
1795 + }
1796 + const firstChild = reconcileChildFibersImpl(
1797 returnFiber,
1798 currentFirstChild,
1814 - init(payload),
1799 + result,
1800 lanes,
1816 - mergeDebugInfo(debugInfo, newChild._debugInfo),
1801 );
1802 + currentDebugInfo = prevDebugInfo;
1803 + return firstChild;
1804 + }
1805 }
1806
1807 if (isArray(newChild)) {
1821 - return reconcileChildrenArray(
1808 + const prevDebugInfo = pushDebugInfo(newChild._debugInfo);
1809 + const firstChild = reconcileChildrenArray(
1810 returnFiber,
1811 currentFirstChild,
1812 newChild,
1813 lanes,
1826 - mergeDebugInfo(debugInfo, newChild._debugInfo),
1814 );
1815 + currentDebugInfo = prevDebugInfo;
1816 + return firstChild;
1817 }
1818
1819 if (getIteratorFn(newChild)) {
1831 - return reconcileChildrenIteratable(
1820 + const prevDebugInfo = pushDebugInfo(newChild._debugInfo);
1821 + const firstChild = reconcileChildrenIteratable(
1822 returnFiber,
1823 currentFirstChild,
1824 newChild,
1825 lanes,
1836 - mergeDebugInfo(debugInfo, newChild._debugInfo),
1826 );
1827 + currentDebugInfo = prevDebugInfo;
1828 + return firstChild;
1829 }
1830
1831 if (
1832 enableAsyncIterableChildren &&
1833 typeof newChild[ASYNC_ITERATOR] === 'function'
1834 ) {
1844 - return reconcileChildrenAsyncIteratable(
1835 + const prevDebugInfo = pushDebugInfo(newChild._debugInfo);
1836 + const firstChild = reconcileChildrenAsyncIteratable(
1837 returnFiber,
1838 currentFirstChild,
1839 newChild,
1840 lanes,
1849 - mergeDebugInfo(debugInfo, newChild._debugInfo),
1841 );
1842 + currentDebugInfo = prevDebugInfo;
1843 + return firstChild;
1844 }
1845
1846 // Usables are a valid React node type. When React encounters a Usable in
@@ -1868,13 +1861,15 @@ function createChildReconciler(
1861 // consider as an future improvement.
1862 if (typeof newChild.then === 'function') {
1863 const thenable: Thenable<any> = (newChild: any);
1871 - return reconcileChildFibersImpl(
1864 + const prevDebugInfo = pushDebugInfo((thenable: any)._debugInfo);
1865 + const firstChild = reconcileChildFibersImpl(
1866 returnFiber,
1867 currentFirstChild,
1868 unwrapThenable(thenable),
1869 lanes,
1876 - mergeDebugInfo(debugInfo, thenable._debugInfo),
1870 );
1871 + currentDebugInfo = prevDebugInfo;
1872 + return firstChild;
1873 }
1874
1875 if (newChild.$$typeof === REACT_CONTEXT_TYPE) {
@@ -1884,7 +1879,6 @@ function createChildReconciler(
1879 currentFirstChild,
1880 readContextDuringReconciliation(returnFiber, context, lanes),
1881 lanes,
1887 - debugInfo,
1882 );
1883 }
1884
@@ -1926,6 +1920,8 @@ function createChildReconciler(
1920 newChild: any,
1921 lanes: Lanes,
1922 ): Fiber | null {
1923 + const prevDebugInfo = currentDebugInfo;
1924 + currentDebugInfo = null;
1925 try {
1926 // This indirection only exists so we can reset `thenableState` at the end.
1927 // It should get inlined by Closure.
@@ -1935,7 +1931,6 @@ function createChildReconciler(
1931 currentFirstChild,
1932 newChild,
1933 lanes,
1938 - null, // debugInfo
1934 );
1935 thenableState = null;
1936 // Don't bother to reset `thenableIndexCounter` to 0 because it always gets
@@ -1963,7 +1958,12 @@ function createChildReconciler(
1958 // the error or suspending if needed.
1959 const throwFiber = createFiberFromThrow(x, returnFiber.mode, lanes);
1960 throwFiber.return = returnFiber;
1961 + if (__DEV__) {
1962 + throwFiber._debugInfo = currentDebugInfo;
1963 + }
1964 return throwFiber;
1965 + } finally {
1966 + currentDebugInfo = prevDebugInfo;
1967 }
1968 }
1969