@samitouri / QOS-React / commits / 8920fc0b2f

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.

Joe Savona committed May 8, 2023 at 13:58 UTC 8920fc0b2f82f8922c082c271503e3c156ed85cc
1 file changed +4 -5
compiler/forget/src/HIR/Dominator.ts
+4 -5
@@ -113,10 +113,9 @@ class Dominator<T> {
113 */
114 get(id: T): T | null {
115 const dominator = this.#nodes.get(id);
116 - invariant(
117 - dominator !== undefined,
118 - `Called on invalid node identifier '${id}'`
119 - );
116 + if (dominator === undefined) {
117 + return null;
118 + }
119 return dominator === id ? null : dominator;
120 }
121
@@ -173,7 +172,7 @@ function computeReverseGraph(fn: HIRFunction): Graph<BlockId> {
172 preds: new Set(eachTerminalSuccessor(block.terminal)),
173 succs: new Set(block.preds),
174 };
176 - if (block.terminal.kind === "return" || block.terminal.kind === "throw") {
175 + if (block.terminal.kind === "return") {
176 node.preds.add(exitId);
177 exit.succs.add(id);
178 }