Repository: facebook/react
Pull request: [Flight] Reduce risk of maximum call stack exceeded when emitting async sequence

The call stack was doubled in https://github.com/facebook/react/pull/35005 by adding a cache wrapper. 

GCC was not able to inline the implementation. We can aid GCC with inlining by refactoring the `return` in the `switch` statement to a single `return` and multiple `break`.

We still need to limit the depth manually or rewrite as an iterative function since we're effectively turning iterative, async loops into recursive calls

## test plan

[bundled code diff for Turbopack](https://react-builds.vercel.app/commits/cc3d32fc300768a47b2eafa276b9d7e5f1ece93f/files/oss-stable-semver/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.node.development.js?compare=fb2177c153353621c5e343b0386993e5084f641e) shows `visitAsyncNodeImpl` has been inlined.

Changed files:
filename: packages/react-server/src/ReactFlightServer.js
patch: @@ -2347,7 +2347,8 @@ function visitAsyncNodeImpl(
     // The technique for debugging the effects of uncached data on the render is to simply uncache it.
     return null;
   }
-  let previousIONode = null;
+
+  let previousIONode: void | null | PromiseNode | IONode = null;
   // First visit anything that blocked this sequence to start in the first place.
   if (node.previous !== null) {
     previousIONode = visitAsyncNode(
@@ -2363,12 +2364,20 @@ function visitAsyncNodeImpl(
       return undefined;
     }
   }
+
+  // `found` represents the return value of the following switch statement.
+  // We can't use multiple `return` statements in the switch statement
+  // since that prevents Closure compiler from inlining `visitAsyncImpl`
+  // thus doubling the call stack size.
+  let found: void | null | PromiseNode | IONode;
   switch (node.tag) {
     case IO_NODE: {
-      return node;
+      found = node;
+      break;
     }
     case UNRESOLVED_PROMISE_NODE: {
-      return previousIONode;
+      found = previousIONode;
+      break;
     }
     case PROMISE_NODE: {
       const awaited = node.awaited;
@@ -2379,7 +2388,8 @@ function visitAsyncNodeImpl(
         if (ioNode === undefined) {
           // Undefined is used as a signal that we found a suitable aborted node and we don't have to find
           // further aborted nodes.
-          return undefined;
+          found = undefined;
+          break;
         } else if (ioNode !== null) {
           // This Promise was blocked on I/O. That's a signal that this Promise is interesting to log.
           // We don't log it yet though. We return it to be logged by the point where it's awaited.
@@ -2436,10 +2446,12 @@ function visitAsyncNodeImpl(
           forwardDebugInfo(request, task, debugInfo);
         }
       }
-      return match;
+      found = match;
+      break;
     }
     case UNRESOLVED_AWAIT_NODE: {
-      return previousIONode;
+      found = previousIONode;
+      break;
     }
     case AWAIT_NODE: {
       const awaited = node.awaited;
@@ -2449,7 +2461,8 @@ function visitAsyncNodeImpl(
         if (ioNode === undefined) {
           // Undefined is used as a signal that we found a suitable aborted node and we don't have to find
           // further aborted nodes.
-          return undefined;
+          found = undefined;
+          break;
         } else if (ioNode !== null) {
           const startTime: number = node.start;
           const endTime: number = node.end;
@@ -2545,13 +2558,15 @@ function visitAsyncNodeImpl(
           forwardDebugInfo(request, task, debugInfo);
         }
       }
-      return match;
+      found = match;
+      break;
     }
     default: {
       // eslint-disable-next-line react-internal/prod-error-codes
       throw new Error('Unknown AsyncSequence tag. This is a bug in React.');
     }
   }
+  return found;
 }
 
 function emitAsyncSequence(