@samitouri / QOS-React-1 / commits / 6dae958eab

[be] Extract computeUnconditionalBlocks() helper

Joe Savona committed Feb 13, 2024 at 16:45 UTC 6dae958eab3b19a6d89ea13242b87ac8cad81e97
4 files changed +43 -59
compiler/packages/babel-plugin-react-forget/src/Entrypoint/Pipeline.ts
+1 -6
@@ -184,12 +184,7 @@ function* runWithEnvironment(
184 }
185
186 if (env.config.validateNoSetStateInRender) {
187 - const noSetStateInRenderResult = validateNoSetStateInRender(hir).unwrap();
188 - yield log({
189 - kind: "debug",
190 - name: "ValidateNoSetStateInRender",
191 - value: noSetStateInRenderResult.debug(),
192 - });
187 + validateNoSetStateInRender(hir).unwrap();
188 }
189
190 inferReactivePlaces(hir);
compiler/packages/babel-plugin-react-forget/src/HIR/ComputeUnconditionalBlocks.ts new
+34
@@ -0,0 +1,34 @@
1 +/*
2 + * Copyright (c) Meta Platforms, Inc. and affiliates.
3 + *
4 + * This source code is licensed under the MIT license found in the
5 + * LICENSE file in the root directory of this source tree.
6 + */
7 +
8 +import { BlockId, HIRFunction, computePostDominatorTree } from ".";
9 +import { CompilerError } from "..";
10 +
11 +export function computeUnconditionalBlocks(fn: HIRFunction): Set<BlockId> {
12 + // Construct the set of blocks that is always reachable from the entry block.
13 + const unconditionalBlocks = new Set<BlockId>();
14 + const dominators = computePostDominatorTree(fn, {
15 + /*
16 + * Hooks must only be in a consistent order for executions that return normally,
17 + * so we opt-in to viewing throw as a non-exit node.
18 + */
19 + includeThrowsAsExitNode: false,
20 + });
21 + const exit = dominators.exit;
22 + let current: BlockId | null = fn.body.entry;
23 + while (current !== null && current !== exit) {
24 + CompilerError.invariant(!unconditionalBlocks.has(current), {
25 + reason:
26 + "Internal error: non-terminating loop in ValidateUnconditionalHooks",
27 + loc: null,
28 + suggestions: null,
29 + });
30 + unconditionalBlocks.add(current);
31 + current = dominators.get(current);
32 + }
33 + return unconditionalBlocks;
34 +}
compiler/packages/babel-plugin-react-forget/src/Validation/ValidateHooksUsage.ts
+2 -23
@@ -10,10 +10,9 @@ import {
10 CompilerErrorDetail,
11 ErrorSeverity,
12 } from "../CompilerError";
13 -import { computePostDominatorTree } from "../HIR";
13 +import { computeUnconditionalBlocks } from "../HIR/ComputeUnconditionalBlocks";
14 import { isHookName } from "../HIR/Environment";
15 import {
16 - BlockId,
16 HIRFunction,
17 IdentifierId,
18 Place,
@@ -88,27 +87,7 @@ function joinKinds(a: Kind, b: Kind): Kind {
87 * See the note for Kind.PotentialHook for sources of potential hooks
88 */
89 export function validateHooksUsage(fn: HIRFunction): void {
91 - // Construct the set of blocks that is always reachable from the entry block.
92 - const unconditionalBlocks = new Set<BlockId>();
93 - const dominators = computePostDominatorTree(fn, {
94 - /*
95 - * Hooks must only be in a consistent order for executions that return normally,
96 - * so we opt-in to viewing throw as a non-exit node.
97 - */
98 - includeThrowsAsExitNode: false,
99 - });
100 - const exit = dominators.exit;
101 - let current: BlockId | null = fn.body.entry;
102 - while (current !== null && current !== exit) {
103 - CompilerError.invariant(!unconditionalBlocks.has(current), {
104 - reason:
105 - "Internal error: non-terminating loop in ValidateUnconditionalHooks",
106 - loc: null,
107 - suggestions: null,
108 - });
109 - unconditionalBlocks.add(current);
110 - current = dominators.get(current);
111 - }
90 + const unconditionalBlocks = computeUnconditionalBlocks(fn);
91
92 const errorsByPlace = new Map<SourceLocation, CompilerErrorDetail>();
93 function recordConditionalHookError(place: Place): void {
compiler/packages/babel-plugin-react-forget/src/Validation/ValidateNoSetStateInRender.ts
+6 -30
@@ -6,15 +6,8 @@
6 */
7
8 import { CompilerError, ErrorSeverity } from "../CompilerError";
9 -import {
10 - BlockId,
11 - HIRFunction,
12 - IdentifierId,
13 - Place,
14 - computePostDominatorTree,
15 - isSetStateType,
16 -} from "../HIR";
17 -import { PostDominator } from "../HIR/Dominator";
9 +import { HIRFunction, IdentifierId, Place, isSetStateType } from "../HIR";
10 +import { computeUnconditionalBlocks } from "../HIR/ComputeUnconditionalBlocks";
11 import { eachInstructionValueOperand } from "../HIR/visitors";
12 import { Err, Ok, Result } from "../Utils/Result";
13
@@ -48,7 +41,7 @@ import { Err, Ok, Result } from "../Utils/Result";
41 */
42 export function validateNoSetStateInRender(
43 fn: HIRFunction
51 -): Result<PostDominator<BlockId>, CompilerError> {
44 +): Result<void, CompilerError> {
45 const unconditionalSetStateFunctions: Set<IdentifierId> = new Set();
46 return validateNoSetStateInRenderImpl(fn, unconditionalSetStateFunctions);
47 }
@@ -56,25 +49,8 @@ export function validateNoSetStateInRender(
49 function validateNoSetStateInRenderImpl(
50 fn: HIRFunction,
51 unconditionalSetStateFunctions: Set<IdentifierId>
59 -): Result<PostDominator<BlockId>, CompilerError> {
60 - // Construct the set of blocks that is always reachable from the entry block.
61 - const unconditionalBlocks = new Set<BlockId>();
62 - const dominators = computePostDominatorTree(fn, {
63 - includeThrowsAsExitNode: false,
64 - });
65 - const exit = dominators.exit;
66 - let current: BlockId | null = fn.body.entry;
67 - while (current !== null && current !== exit) {
68 - CompilerError.invariant(!unconditionalBlocks.has(current), {
69 - reason:
70 - "Internal error: non-terminating loop in ValidateNoSetStateInRender",
71 - loc: null,
72 - suggestions: null,
73 - description: null,
74 - });
75 - unconditionalBlocks.add(current);
76 - current = dominators.get(current);
77 - }
52 +): Result<void, CompilerError> {
53 + const unconditionalBlocks = computeUnconditionalBlocks(fn);
54
55 const errors = new CompilerError();
56 for (const [, block] of fn.body.blocks) {
@@ -140,7 +116,7 @@ function validateNoSetStateInRenderImpl(
116 if (errors.hasErrors()) {
117 return Err(errors);
118 } else {
143 - return Ok(dominators);
119 + return Ok(undefined);
120 }
121 }
122