[HIR] Detect more cases of invalid block nesting
ghstack-source-id: 9e08fa69807ee1b5e99675f9aefc8acd13c16827 Pull Request resolved: https://github.com/facebook/react-forget/pull/2899
Mofei Zhang committed
Apr 26, 2024 at 12:40 UTC
59e37b088b4f7c8711c90a9248701ab6a4c08a21
5 files changed
+94
-11
compiler/packages/babel-plugin-react-forget/src/HIR/AssertValidBlockNesting.ts
+18
-11
@@ -124,17 +124,24 @@ export function assertValidBlockNesting(fn: HIRFunction): void {
124
125
blocks.sort(nestedRangeComparator);
126
127
- for (let i = 1; i < blocks.length; i++) {
128
- const last = blocks[i - 1];
127
+ let active: Array<Block> = [];
128
+ for (let i = 0; i < blocks.length; i++) {
129
const curr = blocks[i];
130
-
131
- const blocksDisjoint = curr.start >= last.end;
132
- const blocksNested = curr.end <= last.end;
133
-
134
- CompilerError.invariant(blocksDisjoint || blocksNested, {
135
- reason: "Invalid nesting in program blocks or scopes",
136
- description: `Blocks overlap but are not nested: ${last.kind}@${last.id}(${last.start}:${last.end}) ${curr.kind}@${curr.id}(${curr.start}:${curr.end})`,
137
- loc: GeneratedSource,
138
- });
130
+ for (let i = active.length - 1; i >= 0; i--) {
131
+ const maybeParent = active[i];
132
+ const disjoint = curr.start >= maybeParent.end;
133
+ const nested = curr.end <= maybeParent.end;
134
+ CompilerError.invariant(disjoint || nested, {
135
+ reason: "Invalid nesting in program blocks or scopes",
136
+ description: `Blocks overlap but are not nested: ${maybeParent.kind}@${maybeParent.id}(${maybeParent.start}:${maybeParent.end}) ${curr.kind}@${curr.id}(${curr.start}:${curr.end})`,
137
+ loc: GeneratedSource,
138
+ });
139
+ if (disjoint) {
140
+ active.length = i;
141
+ } else {
142
+ break;
143
+ }
144
+ }
145
+ active.push(curr);
146
}
147
}
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/error.bug-repro-trycatch-nested-overlapping-range.expect.md
new
+26
@@ -0,0 +1,26 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+function Foo() {
6
+ try {
7
+ let thing = null;
8
+ if (cond) {
9
+ thing = makeObject();
10
+ }
11
+ if (otherCond) {
12
+ mutate(thing);
13
+ }
14
+ } catch {}
15
+}
16
+
17
+```
18
+
19
+
20
+## Error
21
+
22
+```
23
+Invariant: Invalid nesting in program blocks or scopes. Blocks overlap but are not nested: Scope@0(2:24) ProgramBlockSubtree@17(18:26)
24
+```
25
+
26
+
\ No newline at end of file
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/error.bug-repro-trycatch-nested-overlapping-range.js
new
+11
@@ -0,0 +1,11 @@
1
+function Foo() {
2
+ try {
3
+ let thing = null;
4
+ if (cond) {
5
+ thing = makeObject();
6
+ }
7
+ if (otherCond) {
8
+ mutate(thing);
9
+ }
10
+ } catch {}
11
+}
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/error.repro-bug-ref-mutable-range.expect.md
new
+27
@@ -0,0 +1,27 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+function Foo(props, ref) {
6
+ const value = {};
7
+ if (cond1) {
8
+ mutate(value);
9
+ return <Child ref={ref} />;
10
+ }
11
+ mutate(value);
12
+ if (cond2) {
13
+ return <Child ref={identity(ref)} />;
14
+ }
15
+ return value;
16
+}
17
+
18
+```
19
+
20
+
21
+## Error
22
+
23
+```
24
+Invariant: Invalid nesting in program blocks or scopes. Blocks overlap but are not nested: Scope@0(1:21) ProgramBlockSubtree@1(16:23)
25
+```
26
+
27
+
\ No newline at end of file
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/error.repro-bug-ref-mutable-range.js
new
+12
@@ -0,0 +1,12 @@
1
+function Foo(props, ref) {
2
+ const value = {};
3
+ if (cond1) {
4
+ mutate(value);
5
+ return <Child ref={ref} />;
6
+ }
7
+ mutate(value);
8
+ if (cond2) {
9
+ return <Child ref={identity(ref)} />;
10
+ }
11
+ return value;
12
+}