@samitouri / QOS-React-2 / commits / 5aa4143e24

TreeVisitor distinguish blocks from statements

TreeVisitor didn't distinguish between the type of a block and the type of an item that can occur within a block - this was fine for Codegen which can use `t.Statement` for both of those values. However, the upcoming scope construction needs to distinguish instructions in a block from a block itself, so this PR adds a new type parameter.

Joe Savona committed Dec 12, 2022 at 16:46 UTC 5aa4143e2404ee8b993c735ea6c5146e52edca71
8 files changed +87 -35
compiler/forget/src/HIR/Codegen.ts
+1
@@ -93,6 +93,7 @@ class CodegenVisitor
93 implements
94 Visitor<
95 Array<t.Statement>,
96 + t.Statement,
97 Array<t.Statement>,
98 Array<t.Statement>,
99 t.Expression,
compiler/forget/src/HIR/HIRTreeVisitor.ts
+73 -29
@@ -28,6 +28,7 @@ import {
28 * See the {@link Visitor} interface for more about implementing a visitor.
29 */
30 export function visitTree<
31 + TBlockBuilder,
32 TBlock,
33 TInit,
34 TValueBlock,
@@ -36,32 +37,64 @@ export function visitTree<
37 TCase
38 >(
39 fn: HIRFunction,
39 - visitor: Visitor<TBlock, TInit, TValueBlock, TValue, TStatement, TCase>
40 -): TStatement {
40 + visitor: Visitor<
41 + TBlockBuilder,
42 + TBlock,
43 + TInit,
44 + TValueBlock,
45 + TValue,
46 + TStatement,
47 + TCase
48 + >
49 +): TBlock {
50 const cx = new Context(fn.body);
51 const driver = new Driver(cx, visitor);
52 return driver.traverseBlock(cx.block(fn.body.entry));
53 }
54
46 -class Driver<TBlock, TInit, TValueBlock, TValue, TStatement, TCase> {
55 +class Driver<
56 + TBlockBuilder,
57 + TBlock,
58 + TInit,
59 + TValueBlock,
60 + TValue,
61 + TStatement,
62 + TCase
63 +> {
64 cx: Context;
48 - visitor: Visitor<TBlock, TInit, TValueBlock, TValue, TStatement, TCase>;
65 + visitor: Visitor<
66 + TBlockBuilder,
67 + TBlock,
68 + TInit,
69 + TValueBlock,
70 + TValue,
71 + TStatement,
72 + TCase
73 + >;
74
75 constructor(
76 cx: Context,
52 - visitor: Visitor<TBlock, TInit, TValueBlock, TValue, TStatement, TCase>
77 + visitor: Visitor<
78 + TBlockBuilder,
79 + TBlock,
80 + TInit,
81 + TValueBlock,
82 + TValue,
83 + TStatement,
84 + TCase
85 + >
86 ) {
87 this.cx = cx;
88 this.visitor = visitor;
89 }
90
58 - traverseBlock(block: BasicBlock): TStatement {
91 + traverseBlock(block: BasicBlock): TBlock {
92 const blockValue = this.visitor.enterBlock();
93 this.visitBlock(block, blockValue);
94 return this.visitor.leaveBlock(blockValue);
95 }
96
64 - visitBlock(block: BasicBlock, blockValue: TBlock): void {
97 + visitBlock(block: BasicBlock, blockValue: TBlockBuilder): void {
98 invariant(
99 !this.cx.emitted.has(block.id),
100 `Cannot emit the same block twice: bb${block.id}`
@@ -120,19 +153,29 @@ class Driver<TBlock, TInit, TValueBlock, TValue, TStatement, TCase> {
153 }
154
155 this.visitor.visitTerminalId(terminal.id);
123 - let consequent: TStatement | null = null;
156 + let consequent: TBlock | null = null;
157 if (this.cx.isScheduled(terminal.consequent)) {
125 - consequent = this.visitBreak(terminal.consequent);
158 + const break_ = this.visitBreak(terminal.consequent);
159 + if (break_ !== null) {
160 + const builder = this.visitor.enterBlock();
161 + this.visitor.appendBlock(builder, break_);
162 + consequent = this.visitor.leaveBlock(builder);
163 + }
164 } else {
165 consequent = this.traverseBlock(
166 this.cx.ir.blocks.get(terminal.consequent)!
167 );
168 }
169
132 - let alternate: TStatement | null = null;
170 + let alternate: TBlock | null = null;
171 if (alternateId !== null) {
172 if (this.cx.isScheduled(alternateId)) {
135 - alternate = this.visitBreak(alternateId);
173 + const break_ = this.visitBreak(alternateId);
174 + if (break_ !== null) {
175 + const builder = this.visitor.enterBlock();
176 + this.visitor.appendBlock(builder, break_);
177 + alternate = this.visitor.leaveBlock(builder);
178 + }
179 } else {
180 alternate = this.traverseBlock(this.cx.ir.blocks.get(alternateId)!);
181 }
@@ -271,7 +314,7 @@ class Driver<TBlock, TInit, TValueBlock, TValue, TStatement, TCase> {
314 value: testTerminal.test,
315 id: testTerminal.id,
316 });
274 - let loopBody: TStatement;
317 + let loopBody: TBlock;
318 if (loopId) {
319 loopBody = this.traverseBlock(this.cx.ir.blocks.get(loopId)!);
320 } else {
@@ -360,7 +403,7 @@ class Driver<TBlock, TInit, TValueBlock, TValue, TStatement, TCase> {
403 );
404 const updateValue = this.visitValueBlock(blockValue, updateBlock);
405
363 - let loopBody: TStatement;
406 + let loopBody: TBlock;
407 if (loopId) {
408 loopBody = this.traverseBlock(this.cx.ir.blocks.get(loopId)!);
409 } else {
@@ -434,7 +477,7 @@ class Driver<TBlock, TInit, TValueBlock, TValue, TStatement, TCase> {
477 }
478 }
479
437 - visitInitBlock(parent: TBlock, block: BasicBlock): TInit {
480 + visitInitBlock(parent: TBlockBuilder, block: BasicBlock): TInit {
481 const initBlock = this.visitor.enterInitBlock(parent);
482 for (const instr of block.instructions) {
483 const value = this.visitor.visitValue(instr.value, instr.id);
@@ -445,7 +488,7 @@ class Driver<TBlock, TInit, TValueBlock, TValue, TStatement, TCase> {
488 }
489
490 visitValueBlock(
448 - parent: TBlock,
491 + parent: TBlockBuilder,
492 block: BasicBlock,
493 terminalValue?: { value: InstructionValue; id: InstructionId }
494 ): TValue {
@@ -475,7 +518,7 @@ class Driver<TBlock, TInit, TValueBlock, TValue, TStatement, TCase> {
518 return this.visitor.leaveValueBlock(valueBlock, value);
519 }
520
478 - emptyBlock(): TStatement {
521 + emptyBlock(): TBlock {
522 const block = this.visitor.enterBlock();
523 return this.visitor.leaveBlock(block);
524 }
@@ -533,7 +576,7 @@ class Driver<TBlock, TInit, TValueBlock, TValue, TStatement, TCase> {
576 }
577 }
578
536 - visitInstr(instr: Instruction, blockValue: TBlock): void {
579 + visitInstr(instr: Instruction, blockValue: TBlockBuilder): void {
580 const value = this.visitor.visitValue(instr.value, instr.id);
581 const item = this.visitor.visitInstruction(instr, value);
582 this.visitor.appendBlock(blockValue, item);
@@ -775,6 +818,7 @@ type ControlFlowTarget =
818 * TCase = representation of a switch case
819 */
820 export interface Visitor<
821 + TBlockBuilder,
822 TBlock,
823 TInit,
824 TValueBlock,
@@ -786,20 +830,20 @@ export interface Visitor<
830 * Must create an "empty" instance of the visitor's represenation for
831 * the contents of a block.
832 */
789 - enterBlock(): TBlock;
833 + enterBlock(): TBlockBuilder;
834
835 /**
836 * Appends an item onto the given block, with an optional label. The label
837 * indicates that a break/continue will proceed to code *after* the given item.
838 */
795 - appendBlock(block: TBlock, item: TStatement, label?: BlockId): void;
839 + appendBlock(block: TBlockBuilder, item: TStatement, label?: BlockId): void;
840
841 /**
842 * Converts the visitor's block representation into the representation of a
843 * block item, simultaneously "closing" the given block. The block will no
844 * longer be modified by the visitor driver.
845 */
802 - leaveBlock(block: TBlock): TStatement;
846 + leaveBlock(block: TBlockBuilder): TBlock;
847
848 /**
849 * Must create an "empty" instance of the visitor's representation for a value
@@ -809,7 +853,7 @@ export interface Visitor<
853 * The exception is the for initializer, which may contain declarations but not
854 * other statement types.
855 */
812 - enterValueBlock(block: TBlock): TValueBlock;
856 + enterValueBlock(block: TBlockBuilder): TValueBlock;
857
858 /**
859 * Appends an item onto the given value block.
@@ -822,7 +866,7 @@ export interface Visitor<
866 */
867 leaveValueBlock(block: TValueBlock, value: TValue | null): TValue;
868
825 - enterInitBlock(block: TBlock): TValueBlock;
869 + enterInitBlock(block: TBlockBuilder): TValueBlock;
870
871 appendInitBlock(block: TValueBlock, item: TStatement): void;
872
@@ -860,38 +904,38 @@ export interface Visitor<
904 * own representations.
905 */
906 visitTerminal(
863 - terminal: BlockTerminal<TInit, TValue, TStatement, TCase>
907 + terminal: BlockTerminal<TInit, TValue, TBlock, TCase>
908 ): TStatement;
909
910 /**
911 * Visits a switch case statement, which is collected into a switch terminal
912 * variant.
913 */
870 - visitCase(test: TValue | null, block: TStatement): TCase;
914 + visitCase(test: TValue | null, block: TBlock): TCase;
915 }
916
873 -export type BlockTerminal<TInit, TValue, TStatement, TCase> =
917 +export type BlockTerminal<TInit, TValue, TBlock, TCase> =
918 | { kind: "return"; loc: SourceLocation; value: TValue | null }
919 | { kind: "throw"; value: TValue }
920 | {
921 kind: "if";
922 test: TValue;
879 - consequent: TStatement;
880 - alternate: TStatement | null;
923 + consequent: TBlock;
924 + alternate: TBlock | null;
925 }
926 | { kind: "switch"; test: TValue; cases: Array<TCase> }
927 | {
928 kind: "while";
929 loc: SourceLocation;
930 test: TValue;
887 - loop: TStatement;
931 + loop: TBlock;
932 }
933 | {
934 kind: "for";
935 init: TInit;
936 test: TValue;
937 update: TValue;
894 - loop: TStatement;
938 + loop: TBlock;
939 }
940 | { kind: "break"; label: BlockId | null }
941 | { kind: "continue"; label: BlockId | null };
compiler/forget/src/HIR/InferReactiveScopeDependencies.ts
+1 -1
@@ -35,7 +35,7 @@ export function instructionInScope(
35 }
36
37 class ScopeDependenciesVisitor
38 - implements Visitor<void, void, void, InstructionValue, void, void>
38 + implements Visitor<void, void, void, void, InstructionValue, void, void>
39 {
40 #identifiers: Map<Identifier, InstructionId> = new Map();
41 // Scopes that are currently active at this point in the traversal
compiler/forget/src/HIR/InferReactiveScopes.ts
+2 -2
@@ -166,7 +166,7 @@ type ShadowableReactiveScope = {
166 };
167
168 class MergeOverlappingReactiveScopesVisitor
169 - implements Visitor<void, void, void, void, void, void>
169 + implements Visitor<void, void, void, void, void, void, void>
170 {
171 scopes: Array<BlockScope> = [];
172 seenScopes: Set<ScopeId> = new Set();
@@ -332,7 +332,7 @@ type PendingReactiveScope = { active: boolean; scope: ReactiveScope };
332 * were opened (start encountered).
333 */
334 class AlignReactiveScopesToBlockScopeRangeVisitor
335 - implements Visitor<void, void, void, void, void, void>
335 + implements Visitor<void, void, void, void, void, void, void>
336 {
337 // For each block scope (outer array) stores a list of ReactiveScopes that start
338 // in that block scope.
compiler/forget/src/HIR/PrintHIRTree.ts
+1
@@ -29,6 +29,7 @@ class PrintVisitor
29 implements
30 Visitor<
31 Array<string>,
32 + string,
33 Array<string>,
34 Array<string>,
35 string,
compiler/forget/src/__tests__/fixtures/hir/complex-while.expect.md
+3 -1
@@ -81,7 +81,9 @@ flowchart TB
81 function foo$0(a$4, b$5, c$6) {
82 bb1: if (a$4) {
83 while (b$5) {
84 - bb7: if (c$6) break;
84 + bb7: if (c$6) {
85 + break;
86 + }
87 }
88 }
89 }
compiler/forget/src/__tests__/fixtures/hir/mutable-lifetime-loops.expect.md
+3 -1
@@ -230,7 +230,9 @@ function Component$0(props$12) {
230 d$24 = z$19;
231 mutate$7(a$18, b$20);
232
233 - bb4: if (cond$8(a$18)) break;
233 + bb4: if (cond$8(a$18)) {
234 + break;
235 + }
236 }
237
238 bb7: if (a$18) {
compiler/forget/src/__tests__/fixtures/hir/mutable-liverange-loop.expect.md
+3 -1
@@ -210,7 +210,9 @@ function Component$0(props$11) {
210 bb2: while (true) {
211 mutate$6(a$12, b$13);
212
213 - bb4: if (cond$7(a$12)) break;
213 + bb4: if (cond$7(a$12)) {
214 + break;
215 + }
216 }
217
218 bb7: if (a$12) {