HIR terminal for representing reactive scopes
ghstack-source-id: f7d5b68bc5217555b6060ade3bfa253bb15660ad Pull Request resolved: https://github.com/facebook/react-forget/pull/2830
Joe Savona committed
Apr 8, 2024 at 17:43 UTC
57d746e3c4a89aefb9ec59912120ea284e74e1c5
5 files changed
+87
-5
compiler/packages/babel-plugin-react-forget/src/HIR/HIR.ts
+11
-1
@@ -347,7 +347,8 @@ export type Terminal =
347
| LabelTerminal
348
| SequenceTerminal
349
| MaybeThrowTerminal
350
- | TryTerminal;
350
+ | TryTerminal
351
+ | ReactiveScopeTerminal;
352
353
function _staticInvariantTerminalHasLocation(
354
terminal: Terminal
@@ -543,6 +544,15 @@ export type MaybeThrowTerminal = {
544
loc: SourceLocation;
545
};
546
547
+export type ReactiveScopeTerminal = {
548
+ kind: "scope";
549
+ fallthrough: BlockId;
550
+ block: BlockId;
551
+ scope: ReactiveScope;
552
+ id: InstructionId;
553
+ loc: SourceLocation;
554
+};
555
+
556
/*
557
* Instructions generally represent expressions but with all nesting flattened away,
558
* such that all operands to each instruction are either primitive values OR are
compiler/packages/babel-plugin-react-forget/src/HIR/HIRBuilder.ts
+4
@@ -795,6 +795,10 @@ function getReversePostorderedBlocks(func: HIR): HIR["blocks"] {
795
visit(terminal.block);
796
break;
797
}
798
+ case "scope": {
799
+ visit(terminal.block);
800
+ break;
801
+ }
802
case "unsupported": {
803
break;
804
}
compiler/packages/babel-plugin-react-forget/src/HIR/PrintHIR.ts
+9
-1
@@ -8,6 +8,7 @@
8
import generate from "@babel/generator";
9
import { printReactiveFunction } from "..";
10
import { CompilerError } from "../CompilerError";
11
+import { printReactiveScopeSummary } from "../ReactiveScopes/PrintReactiveFunction";
12
import DisjointSet from "../Utils/DisjointSet";
13
import { assertExhaustive } from "../Utils/utils";
14
import type {
@@ -124,7 +125,8 @@ export function printMixedHIR(
125
case "goto":
126
case "do-while":
127
case "for-in":
127
- case "for-of": {
128
+ case "for-of":
129
+ case "scope": {
130
const terminal = printTerminal(value);
131
if (Array.isArray(terminal)) {
132
return terminal.join("; ");
@@ -267,6 +269,12 @@ export function printTerminal(terminal: Terminal): Array<string> | string {
269
value = `MaybeThrow continuation=bb${terminal.continuation} handler=bb${terminal.handler}`;
270
break;
271
}
272
+ case "scope": {
273
+ value = `Scope ${printReactiveScopeSummary(terminal.scope)} block=bb${
274
+ terminal.block
275
+ } fallthrough=bb${terminal.fallthrough}`;
276
+ break;
277
+ }
278
case "try": {
279
value = `Try block=bb${terminal.block} handler=bb${terminal.handler}${
280
terminal.handlerBinding !== null
compiler/packages/babel-plugin-react-forget/src/HIR/visitors.ts
+32
-3
@@ -833,6 +833,18 @@ export function mapTerminalSuccessors(
833
loc: terminal.loc,
834
};
835
}
836
+ case "scope": {
837
+ const block = fn(terminal.block);
838
+ const fallthrough = fn(terminal.fallthrough);
839
+ return {
840
+ kind: "scope",
841
+ scope: terminal.scope,
842
+ block,
843
+ fallthrough,
844
+ id: makeInstructionId(0),
845
+ loc: terminal.loc,
846
+ };
847
+ }
848
case "unsupported": {
849
return terminal;
850
}
@@ -872,7 +884,8 @@ export function terminalFallthrough(terminal: Terminal): BlockId | null {
884
case "sequence":
885
case "switch":
886
case "ternary":
875
- case "while": {
887
+ case "while":
888
+ case "scope": {
889
return terminal.fallthrough;
890
}
891
default: {
@@ -935,21 +948,31 @@ export function mapOptionalFallthroughs(
948
const _: BlockId = terminal.fallthrough;
949
break;
950
}
951
+ case "scope": {
952
+ const _: BlockId = terminal.fallthrough;
953
+ break;
954
+ }
955
case "switch": {
956
if (terminal.fallthrough !== null) {
957
terminal.fallthrough = fn(terminal.fallthrough);
958
+ } else {
959
+ terminal.fallthrough = null;
960
}
961
break;
962
}
963
case "if": {
964
if (terminal.fallthrough !== null) {
965
terminal.fallthrough = fn(terminal.fallthrough);
966
+ } else {
967
+ terminal.fallthrough = null;
968
}
969
break;
970
}
971
case "label": {
972
if (terminal.fallthrough !== null) {
973
terminal.fallthrough = fn(terminal.fallthrough);
974
+ } else {
975
+ terminal.fallthrough = null;
976
}
977
break;
978
}
@@ -1050,6 +1073,10 @@ export function* eachTerminalSuccessor(terminal: Terminal): Iterable<BlockId> {
1073
yield terminal.block;
1074
break;
1075
}
1076
+ case "scope": {
1077
+ yield terminal.block;
1078
+ break;
1079
+ }
1080
case "unsupported":
1081
break;
1082
default: {
@@ -1109,7 +1136,8 @@ export function mapTerminalOperands(
1136
case "for-of":
1137
case "for-in":
1138
case "goto":
1112
- case "unsupported": {
1139
+ case "unsupported":
1140
+ case "scope": {
1141
// no-op
1142
break;
1143
}
@@ -1165,7 +1193,8 @@ export function* eachTerminalOperand(terminal: Terminal): Iterable<Place> {
1193
case "for-of":
1194
case "for-in":
1195
case "goto":
1168
- case "unsupported": {
1196
+ case "unsupported":
1197
+ case "scope": {
1198
// no-op
1199
break;
1200
}
compiler/packages/babel-plugin-react-forget/src/ReactiveScopes/BuildReactiveFunction.ts
+31
@@ -786,6 +786,37 @@ class Driver {
786
}
787
break;
788
}
789
+ case "scope": {
790
+ const fallthroughId = !this.cx.isScheduled(terminal.fallthrough)
791
+ ? terminal.fallthrough
792
+ : null;
793
+ if (fallthroughId !== null) {
794
+ const scheduleId = this.cx.schedule(fallthroughId, "if");
795
+ scheduleIds.push(scheduleId);
796
+ }
797
+
798
+ let block: ReactiveBlock;
799
+ if (this.cx.isScheduled(terminal.block)) {
800
+ CompilerError.invariant(false, {
801
+ reason: `Unexpected 'scope' where the block is already scheduled`,
802
+ loc: terminal.loc,
803
+ });
804
+ } else {
805
+ block = this.traverseBlock(this.cx.ir.blocks.get(terminal.block)!);
806
+ }
807
+
808
+ this.cx.unscheduleAll(scheduleIds);
809
+ blockValue.push({
810
+ kind: "scope",
811
+ instructions: block,
812
+ scope: terminal.scope,
813
+ });
814
+ if (fallthroughId !== null) {
815
+ this.visitBlock(this.cx.ir.blocks.get(fallthroughId)!, blockValue);
816
+ }
817
+
818
+ break;
819
+ }
820
case "unsupported": {
821
CompilerError.invariant(false, {
822
reason: "Unexpected unsupported terminal",