From 8920fc0b2f82f8922c082c271503e3c156ed85cc Mon Sep 17 00:00:00 2001 From: Joe Savona Date: Mon, 8 May 2023 13:58:46 -0700 Subject: [PATCH] Dont count throw as an exit node (React semantics) React will retry or abort components that throw (depending on a few conditions), so from React's perspective a `throw` statement is not a normal exit node. Thus the Rules of Hooks really have a caveat: the set of hooks that are called _in an execution that returns successfully_ must be consistent. Examples such as the following are therefore allowed: ```javascript function Component(props) { if (props.cond) { throw new Error(...); } useHook(); } ``` By modeling `throw` as an exit node, we rejected cases such as this. This diff changes to not model throws as exit nodes. #1584 changes this to make it an option, since some cases will want to consider throw as an exit node. --- compiler/forget/src/HIR/Dominator.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/compiler/forget/src/HIR/Dominator.ts b/compiler/forget/src/HIR/Dominator.ts index b53fe41d7e..e4a50c73ad 100644 --- a/compiler/forget/src/HIR/Dominator.ts +++ b/compiler/forget/src/HIR/Dominator.ts @@ -113,10 +113,9 @@ class Dominator { */ get(id: T): T | null { const dominator = this.#nodes.get(id); - invariant( - dominator !== undefined, - `Called on invalid node identifier '${id}'` - ); + if (dominator === undefined) { + return null; + } return dominator === id ? null : dominator; } @@ -173,7 +172,7 @@ function computeReverseGraph(fn: HIRFunction): Graph { preds: new Set(eachTerminalSuccessor(block.terminal)), succs: new Set(block.preds), }; - if (block.terminal.kind === "return" || block.terminal.kind === "throw") { + if (block.terminal.kind === "return") { node.preds.add(exitId); exit.succs.add(id); }