Validator pass that terminal successors all exist
Joe Savona committed
Apr 4, 2023 at 13:29 UTC
d660f37bf22dec1ffcad309bf3c8aa9e2b0d8eef
6 files changed
+62
-1
compiler/forget/src/CompilerPipeline.ts
+3
-1
@@ -11,9 +11,10 @@ import {
11
lower,
12
mergeConsecutiveBlocks,
13
ReactiveFunction,
14
+ validateConsistentIdentifiers,
15
+ validateTerminalSuccessors,
16
} from "./HIR";
17
import { Environment, EnvironmentConfig } from "./HIR/Environment";
16
-import { validateConsistentIdentifiers } from "./HIR/ValidateConsistentIdentifiers";
18
import {
19
analyseFunctions,
20
dropMemoCalls,
@@ -61,6 +62,7 @@ export function* run(
62
yield log({ kind: "hir", name: "MergeConsecutiveBlocks", value: hir });
63
64
validateConsistentIdentifiers(hir);
65
+ validateTerminalSuccessors(hir);
66
67
enterSSA(hir);
68
yield log({ kind: "hir", name: "SSA", value: hir });
compiler/forget/src/HIR/ValidateTerminalSuccessors.ts
new
+27
@@ -0,0 +1,27 @@
1
+/**
2
+ * Copyright (c) Facebook, Inc. and its 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 { CompilerError } from "../CompilerError";
9
+import { GeneratedSource, HIRFunction } from "./HIR";
10
+import { printTerminal } from "./PrintHIR";
11
+import { mapTerminalSuccessors } from "./visitors";
12
+
13
+export function validateTerminalSuccessors(fn: HIRFunction): void {
14
+ for (const [, block] of fn.body.blocks) {
15
+ mapTerminalSuccessors(block.terminal, (successor) => {
16
+ if (!fn.body.blocks.has(successor)) {
17
+ CompilerError.invariant(
18
+ `Block bb${successor} does not exist for terminal '${printTerminal(
19
+ block.terminal
20
+ )}'`,
21
+ (block.terminal as any).loc ?? GeneratedSource
22
+ );
23
+ }
24
+ return successor;
25
+ });
26
+ }
27
+}
compiler/forget/src/HIR/index.ts
+2
@@ -17,3 +17,5 @@ export {
17
} from "./HIRBuilder";
18
export { mergeConsecutiveBlocks } from "./MergeConsecutiveBlocks";
19
export { printFunction, printHIR } from "./PrintHIR";
20
+export { validateConsistentIdentifiers } from "./ValidateConsistentIdentifiers";
21
+export { validateTerminalSuccessors } from "./ValidateTerminalSuccessors";
compiler/forget/src/Optimization/ConstantPropagation.ts
+5
@@ -21,6 +21,8 @@ import {
21
removeUnreachableFallthroughs,
22
reversePostorderBlocks,
23
shrink,
24
+ validateConsistentIdentifiers,
25
+ validateTerminalSuccessors,
26
} from "../HIR";
27
import { removeDeadDoWhileStatements } from "../HIR/HIRBuilder";
28
import { eliminateRedundantPhi } from "../SSA";
@@ -70,6 +72,9 @@ export function constantPropagation(fn: HIRFunction): void {
72
// Finally, merge together any blocks that are now guaranteed to execute
73
// consecutively
74
mergeConsecutiveBlocks(fn);
75
+
76
+ validateConsistentIdentifiers(fn);
77
+ validateTerminalSuccessors(fn);
78
}
79
}
80
compiler/forget/src/__tests__/fixtures/compiler/error.for-return.expect.md
new
+20
@@ -0,0 +1,20 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+function Component(props) {
6
+ for (let i = 0; i < props.count; i++) {
7
+ return;
8
+ }
9
+}
10
+
11
+```
12
+
13
+
14
+## Error
15
+
16
+```
17
+[ReactForget] Invariant: Block bb4 does not exist for terminal '[1] For init=bb3 test=bb1 loop=bb5 update=bb4 fallthrough=bb2' (2:4)
18
+```
19
+
20
+
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/compiler/error.for-return.js
new
+5
@@ -0,0 +1,5 @@
1
+function Component(props) {
2
+ for (let i = 0; i < props.count; i++) {
3
+ return;
4
+ }
5
+}