Add support for DoWhile statements
Adds support for DoWhileStatements. It's pretty similar to how we handle While, except in the case where a test block is unreachable (for example, an early unconditional `break` within the loop body). In this scenario we eliminate the terminal altogether and replace it with a goto to the loop block.
Lauren Tan committed
Mar 1, 2023 at 19:45 UTC
440fd1f24abe340801baeca594d844d609c902b9
26 files changed
+533
-67
compiler/forget/src/HIR/BuildHIR.ts
+53
-1
@@ -644,9 +644,61 @@ function lowerStatement(
644
});
645
return;
646
}
647
+ case "DoWhileStatement": {
648
+ const stmt = stmtPath as NodePath<t.DoWhileStatement>;
649
+ // Block used to evaluate whether to (re)enter or exit the loop
650
+ const conditionalBlock = builder.reserve("loop");
651
+ // Block for code following the loop
652
+ const continuationBlock = builder.reserve("block");
653
+ // Loop body, executed at least once uncondtionally prior to exit
654
+ const loopBlock = builder.enter("block", (_loopBlockId) => {
655
+ return builder.loop(
656
+ label,
657
+ conditionalBlock.id,
658
+ continuationBlock.id,
659
+ () => {
660
+ lowerStatement(builder, stmt.get("body"));
661
+ return {
662
+ kind: "goto",
663
+ block: conditionalBlock.id,
664
+ variant: GotoVariant.Continue,
665
+ id: makeInstructionId(0),
666
+ };
667
+ }
668
+ );
669
+ });
670
+ // Jump to the conditional block to evaluate whether to (re)enter the loop or exit to the
671
+ // continuation block.
672
+ const loc = stmt.node.loc ?? GeneratedSource;
673
+ builder.terminateWithContinuation(
674
+ {
675
+ kind: "do-while",
676
+ loc,
677
+ test: conditionalBlock.id,
678
+ loop: loopBlock,
679
+ fallthrough: continuationBlock.id,
680
+ id: makeInstructionId(0),
681
+ },
682
+ conditionalBlock
683
+ );
684
+ /**
685
+ * The conditional block is empty and exists solely as conditional for
686
+ * (re)entering or exiting the loop
687
+ */
688
+ const test = lowerExpressionToTemporary(builder, stmt.get("test"));
689
+ const terminal: BranchTerminal = {
690
+ kind: "branch",
691
+ test,
692
+ consequent: loopBlock,
693
+ alternate: continuationBlock.id,
694
+ id: makeInstructionId(0),
695
+ };
696
+ // Complete the conditional and continue with code after the loop
697
+ builder.terminateWithContinuation(terminal, continuationBlock);
698
+ return;
699
+ }
700
case "ForOfStatement":
701
case "ForInStatement":
649
- case "DoWhileStatement":
702
case "ClassDeclaration":
703
case "DebuggerStatement":
704
case "DeclareClass":
compiler/forget/src/HIR/HIR.ts
+17
@@ -122,6 +122,7 @@ export type ReactiveTerminal =
122
| ReactiveReturnTerminal
123
| ReactiveThrowTerminal
124
| ReactiveSwitchTerminal
125
+ | ReactiveDoWhileTerminal
126
| ReactiveWhileTerminal
127
| ReactiveForTerminal
128
| ReactiveIfTerminal;
@@ -157,6 +158,12 @@ export type ReactiveSwitchTerminal = {
158
}>;
159
id: InstructionId;
160
};
161
+export type ReactiveDoWhileTerminal = {
162
+ kind: "do-while";
163
+ loop: ReactiveBlock;
164
+ test: ReactiveValue;
165
+ id: InstructionId;
166
+};
167
export type ReactiveWhileTerminal = {
168
kind: "while";
169
test: ReactiveValue;
@@ -241,6 +248,7 @@ export type Terminal =
248
| BranchTerminal
249
| SwitchTerminal
250
| ForTerminal
251
+ | DoWhileTerminal
252
| WhileTerminal
253
| LogicalTerminal
254
| TernaryTerminal;
@@ -298,6 +306,15 @@ export type SwitchTerminal = {
306
id: InstructionId;
307
};
308
309
+export type DoWhileTerminal = {
310
+ kind: "do-while";
311
+ loop: BlockId;
312
+ test: BlockId;
313
+ fallthrough: BlockId;
314
+ id: InstructionId;
315
+ loc: SourceLocation;
316
+};
317
+
318
export type WhileTerminal = {
319
kind: "while";
320
loc: SourceLocation;
compiler/forget/src/HIR/HIRBuilder.ts
+29
@@ -264,6 +264,7 @@ export default class HIRBuilder {
264
// then convert to reverse postorder
265
reversePostorderBlocks(ir);
266
removeUnreachableFallthroughs(ir);
267
+ removeDeadDoWhileStatements(ir);
268
markInstructionIds(ir);
269
markPredecessors(ir);
270
@@ -530,6 +531,30 @@ export function removeUnreachableFallthroughs(func: HIR): void {
531
}
532
}
533
}
534
+
535
+export function removeDeadDoWhileStatements(func: HIR): void {
536
+ const visited: Set<BlockId> = new Set();
537
+ for (const [_, block] of func.blocks) {
538
+ visited.add(block.id);
539
+ }
540
+
541
+ // If the test condition of a DoWhile is unreachable, the terminal is effectively deadcode and we
542
+ // can just inline the loop body. We replace the terminal with a goto to the loop block and
543
+ // MergeConsecutiveBlocks figures out how to merge as appropriate.
544
+ for (const [_, block] of func.blocks) {
545
+ if (block.terminal.kind === "do-while") {
546
+ if (!visited.has(block.terminal.test)) {
547
+ block.terminal = {
548
+ kind: "goto",
549
+ block: block.terminal.loop,
550
+ variant: GotoVariant.Break,
551
+ id: block.terminal.id,
552
+ };
553
+ }
554
+ }
555
+ }
556
+}
557
+
558
/**
559
* Converts the graph to reverse-postorder, with predecessor blocks appearing
560
* before successors except in the case of back links (ie loops).
@@ -604,6 +629,10 @@ export function reversePostorderBlocks(func: HIR): void {
629
visit(terminal.test);
630
break;
631
}
632
+ case "do-while": {
633
+ visit(terminal.loop);
634
+ break;
635
+ }
636
case "while": {
637
visit(terminal.test);
638
break;
compiler/forget/src/HIR/PrintHIR.ts
+8
-1
@@ -87,7 +87,8 @@ export function printMixedHIR(
87
case "while":
88
case "for":
89
case "unsupported":
90
- case "goto": {
90
+ case "goto":
91
+ case "do-while": {
92
const terminal = printTerminal(value);
93
if (Array.isArray(terminal)) {
94
return terminal.join("; ");
@@ -184,6 +185,12 @@ export function printTerminal(terminal: Terminal): Array<string> | string {
185
value = output;
186
break;
187
}
188
+ case "do-while": {
189
+ value = `[${terminal.id}] DoWhile loop=${`bb${terminal.loop}`} test=bb${
190
+ terminal.test
191
+ } fallthrough=${`bb${terminal.fallthrough}`}`;
192
+ break;
193
+ }
194
case "while": {
195
value = `[${terminal.id}] While test=bb${terminal.test} loop=${
196
terminal.loop !== null ? `bb${terminal.loop}` : ""
compiler/forget/src/HIR/visitors.ts
+19
@@ -366,6 +366,19 @@ export function mapTerminalSuccessors(
366
case "throw": {
367
return terminal;
368
}
369
+ case "do-while": {
370
+ const loop = fn(terminal.loop);
371
+ const test = fn(terminal.test);
372
+ const fallthrough = fn(terminal.fallthrough);
373
+ return {
374
+ kind: "do-while",
375
+ loc: terminal.loc,
376
+ test,
377
+ loop,
378
+ fallthrough,
379
+ id: makeInstructionId(0),
380
+ };
381
+ }
382
case "while": {
383
const test = fn(terminal.test);
384
const loop = fn(terminal.loop);
@@ -446,6 +459,10 @@ export function* eachTerminalSuccessor(terminal: Terminal): Iterable<BlockId> {
459
case "throw": {
460
break;
461
}
462
+ case "do-while": {
463
+ yield terminal.loop;
464
+ break;
465
+ }
466
case "while": {
467
yield terminal.test;
468
break;
@@ -497,6 +514,7 @@ export function mapTerminalOperands(
514
}
515
case "ternary":
516
case "logical":
517
+ case "do-while":
518
case "while":
519
case "for":
520
case "goto":
@@ -542,6 +560,7 @@ export function* eachTerminalOperand(terminal: Terminal): Iterable<Place> {
560
}
561
case "ternary":
562
case "logical":
563
+ case "do-while":
564
case "while":
565
case "for":
566
case "goto":
compiler/forget/src/Optimization/ConstantPropagation.ts
+2
@@ -22,6 +22,7 @@ import {
22
reversePostorderBlocks,
23
shrink,
24
} from "../HIR";
25
+import { removeDeadDoWhileStatements } from "../HIR/HIRBuilder";
26
import { eliminateRedundantPhi } from "../SSA";
27
28
/**
@@ -49,6 +50,7 @@ export function constantPropagation(fn: HIRFunction): void {
50
shrink(fn.body);
51
reversePostorderBlocks(fn.body);
52
removeUnreachableFallthroughs(fn.body);
53
+ removeDeadDoWhileStatements(fn.body);
54
markInstructionIds(fn.body);
55
markPredecessors(fn.body);
56
compiler/forget/src/ReactiveScopes/BuildReactiveFunction.ts
+49
@@ -231,6 +231,55 @@ class Driver {
231
}
232
break;
233
}
234
+ case "do-while": {
235
+ const fallthroughId = !this.cx.isScheduled(terminal.fallthrough)
236
+ ? terminal.fallthrough
237
+ : null;
238
+ const loopId =
239
+ !this.cx.isScheduled(terminal.loop) &&
240
+ terminal.loop !== terminal.fallthrough
241
+ ? terminal.loop
242
+ : null;
243
+ const scheduleId = this.cx.scheduleLoop(
244
+ terminal.fallthrough,
245
+ terminal.test,
246
+ terminal.loop
247
+ );
248
+ scheduleIds.push(scheduleId);
249
+
250
+ let loopBody: ReactiveBlock;
251
+ if (loopId) {
252
+ loopBody = this.traverseBlock(this.cx.ir.blocks.get(loopId)!);
253
+ } else {
254
+ const break_ = this.visitBreak(terminal.loop, null);
255
+ invariant(
256
+ break_ !== null,
257
+ "If loop body is already scheduled it must be a break"
258
+ );
259
+ loopBody = [break_];
260
+ }
261
+
262
+ const testValue = this.visitValueBlock(
263
+ terminal.test,
264
+ terminal.loc
265
+ ).value;
266
+
267
+ this.cx.unscheduleAll(scheduleIds);
268
+ blockValue.push({
269
+ kind: "terminal",
270
+ terminal: {
271
+ kind: "do-while",
272
+ test: testValue,
273
+ loop: loopBody,
274
+ id: terminal.id,
275
+ },
276
+ label: fallthroughId,
277
+ });
278
+ if (fallthroughId !== null) {
279
+ this.visitBlock(this.cx.ir.blocks.get(fallthroughId)!, blockValue);
280
+ }
281
+ break;
282
+ }
283
case "while": {
284
const fallthroughId =
285
terminal.fallthrough !== null &&
compiler/forget/src/ReactiveScopes/CodegenReactiveFunction.ts
+4
@@ -340,6 +340,10 @@ function codegenTerminal(
340
case "throw": {
341
return t.throwStatement(codegenPlace(cx, terminal.value));
342
}
343
+ case "do-while": {
344
+ const test = codegenInstructionValue(cx, terminal.test);
345
+ return t.doWhileStatement(test, codegenBlock(cx, terminal.loop));
346
+ }
347
case "while": {
348
const test = codegenInstructionValue(cx, terminal.test);
349
return t.whileStatement(test, codegenBlock(cx, terminal.loop));
compiler/forget/src/ReactiveScopes/FlattenReactiveLoops.ts
+1
@@ -46,6 +46,7 @@ class Transform extends ReactiveFunctionTransform<boolean> {
46
): void {
47
switch (stmt.terminal.kind) {
48
// Loop terminals flatten nested scopes
49
+ case "do-while":
50
case "while":
51
case "for": {
52
this.traverseTerminal(stmt, true);
compiler/forget/src/ReactiveScopes/PropagateScopeDependencies.ts
+5
@@ -578,6 +578,11 @@ function visit(context: Context, block: ReactiveBlock): void {
578
});
579
break;
580
}
581
+ case "do-while": {
582
+ visit(context, terminal.loop);
583
+ visitReactiveValue(context, terminal.test);
584
+ break;
585
+ }
586
case "while": {
587
visitReactiveValue(context, terminal.test);
588
context.enterConditional(() => {
compiler/forget/src/ReactiveScopes/visitors.ts
+6
@@ -106,6 +106,11 @@ export class ReactiveFunctionVisitor<TState = void> {
106
this.visitBlock(terminal.loop, state);
107
break;
108
}
109
+ case "do-while": {
110
+ this.visitBlock(terminal.loop, state);
111
+ this.visitValue(terminal.id, terminal.test, state);
112
+ break;
113
+ }
114
case "while": {
115
this.visitValue(terminal.id, terminal.test, state);
116
this.visitBlock(terminal.loop, state);
@@ -309,6 +314,7 @@ export function mapTerminalBlocks(
314
terminal.loop = fn(terminal.loop);
315
break;
316
}
317
+ case "do-while":
318
case "while": {
319
terminal.loop = fn(terminal.loop);
320
break;
compiler/forget/src/Utils/VisualizeHIRMermaid.ts
+10
@@ -107,6 +107,10 @@ function printTerminalLabel(terminal: Terminal): string {
107
buffer.push("Ternary");
108
break;
109
}
110
+ case "do-while": {
111
+ buffer.push("DoWhile");
112
+ break;
113
+ }
114
case "while":
115
buffer.push("While");
116
break;
@@ -174,6 +178,12 @@ function printTerminalArrows(blockId: BlockId, terminal: Terminal): string {
178
}
179
break;
180
}
181
+ case "do-while": {
182
+ buffer.push(printJumpArrow(blockId, terminal.loop, "loop"));
183
+ buffer.push(printJumpArrow(blockId, terminal.test, "test"));
184
+ buffer.push(printJumpArrow(blockId, terminal.fallthrough, "fallthrough"));
185
+ break;
186
+ }
187
case "while": {
188
buffer.push(printJumpArrow(blockId, terminal.test, "test"));
189
buffer.push(printJumpArrow(blockId, terminal.loop, "loop"));
compiler/forget/src/__tests__/fixtures/hir/do-while-break.expect.md
new
+22
@@ -0,0 +1,22 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+function Component(props) {
6
+ do {
7
+ break;
8
+ } while (props.cond);
9
+ return props;
10
+}
11
+
12
+```
13
+
14
+## Code
15
+
16
+```javascript
17
+function Component(props) {
18
+ return props;
19
+}
20
+
21
+```
22
+
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/hir/do-while-break.js
new
+6
@@ -0,0 +1,6 @@
1
+function Component(props) {
2
+ do {
3
+ break;
4
+ } while (props.cond);
5
+ return props;
6
+}
compiler/forget/src/__tests__/fixtures/hir/do-while-compound-test.expect.md
new
+40
@@ -0,0 +1,40 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+function Component(props) {
6
+ let x = [1, 2, 3];
7
+ let ret = [];
8
+ do {
9
+ let item = x.pop();
10
+ ret.push(item * 2);
11
+ } while (x.length && props.cond);
12
+ return ret;
13
+}
14
+
15
+```
16
+
17
+## Code
18
+
19
+```javascript
20
+function Component(props) {
21
+ const $ = React.unstable_useMemoCache(2);
22
+ const c_0 = $[0] !== props;
23
+ let ret;
24
+ if (c_0) {
25
+ const x = [1, 2, 3];
26
+ ret = [];
27
+ do {
28
+ const item = x.pop();
29
+ ret.push(item * 2);
30
+ } while (x.length && props.cond);
31
+ $[0] = props;
32
+ $[1] = ret;
33
+ } else {
34
+ ret = $[1];
35
+ }
36
+ return ret;
37
+}
38
+
39
+```
40
+
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/hir/do-while-compound-test.js
new
+9
@@ -0,0 +1,9 @@
1
+function Component(props) {
2
+ let x = [1, 2, 3];
3
+ let ret = [];
4
+ do {
5
+ let item = x.pop();
6
+ ret.push(item * 2);
7
+ } while (x.length && props.cond);
8
+ return ret;
9
+}
compiler/forget/src/__tests__/fixtures/hir/do-while-conditional-break.expect.md
new
+43
@@ -0,0 +1,43 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+function Component(props) {
6
+ let x = [0, 1, 2, 3];
7
+ do {
8
+ if (x === 0) {
9
+ break;
10
+ }
11
+ mutate(x);
12
+ } while (props.cond);
13
+ return x;
14
+}
15
+
16
+```
17
+
18
+## Code
19
+
20
+```javascript
21
+function Component(props) {
22
+ const $ = React.unstable_useMemoCache(2);
23
+ const c_0 = $[0] !== props.cond;
24
+ let x;
25
+ if (c_0) {
26
+ x = [0, 1, 2, 3];
27
+ do {
28
+ if (x === 0) {
29
+ break;
30
+ }
31
+
32
+ mutate(x);
33
+ } while (props.cond);
34
+ $[0] = props.cond;
35
+ $[1] = x;
36
+ } else {
37
+ x = $[1];
38
+ }
39
+ return x;
40
+}
41
+
42
+```
43
+
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/hir/do-while-conditional-break.js
new
+10
@@ -0,0 +1,10 @@
1
+function Component(props) {
2
+ let x = [0, 1, 2, 3];
3
+ do {
4
+ if (x === 0) {
5
+ break;
6
+ }
7
+ mutate(x);
8
+ } while (props.cond);
9
+ return x;
10
+}
compiler/forget/src/__tests__/fixtures/hir/do-while-continue.expect.md
new
+46
@@ -0,0 +1,46 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+function Component() {
6
+ const x = [0, 1, 2, 3];
7
+ const ret = [];
8
+ do {
9
+ const item = x.pop();
10
+ if (item === 0) {
11
+ continue;
12
+ }
13
+ ret.push(item / 2);
14
+ } while (x.length);
15
+
16
+ return ret;
17
+}
18
+
19
+```
20
+
21
+## Code
22
+
23
+```javascript
24
+function Component() {
25
+ const $ = React.unstable_useMemoCache(1);
26
+ let ret;
27
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
28
+ const x = [0, 1, 2, 3];
29
+ ret = [];
30
+ do {
31
+ const item = x.pop();
32
+ if (item === 0) {
33
+ continue;
34
+ }
35
+
36
+ ret.push(item / 2);
37
+ } while (x.length);
38
+ $[0] = ret;
39
+ } else {
40
+ ret = $[0];
41
+ }
42
+ return ret;
43
+}
44
+
45
+```
46
+
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/hir/do-while-continue.js
new
+13
@@ -0,0 +1,13 @@
1
+function Component() {
2
+ const x = [0, 1, 2, 3];
3
+ const ret = [];
4
+ do {
5
+ const item = x.pop();
6
+ if (item === 0) {
7
+ continue;
8
+ }
9
+ ret.push(item / 2);
10
+ } while (x.length);
11
+
12
+ return ret;
13
+}
compiler/forget/src/__tests__/fixtures/hir/do-while-early-unconditional-break.expect.md
new
+34
@@ -0,0 +1,34 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+function Component(props) {
6
+ let x = [1, 2, 3];
7
+ do {
8
+ mutate(x);
9
+ break;
10
+ } while (props.cond);
11
+ return x;
12
+}
13
+
14
+```
15
+
16
+## Code
17
+
18
+```javascript
19
+function Component(props) {
20
+ const $ = React.unstable_useMemoCache(1);
21
+ let x;
22
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
23
+ x = [1, 2, 3];
24
+
25
+ mutate(x);
26
+ $[0] = x;
27
+ } else {
28
+ x = $[0];
29
+ }
30
+ return x;
31
+}
32
+
33
+```
34
+
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/hir/do-while-early-unconditional-break.js
new
+8
@@ -0,0 +1,8 @@
1
+function Component(props) {
2
+ let x = [1, 2, 3];
3
+ do {
4
+ mutate(x);
5
+ break;
6
+ } while (props.cond);
7
+ return x;
8
+}
compiler/forget/src/__tests__/fixtures/hir/do-while-simple.expect.md
new
+38
@@ -0,0 +1,38 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+function Component() {
6
+ let x = [1, 2, 3];
7
+ let ret = [];
8
+ do {
9
+ let item = x.pop();
10
+ ret.push(item * 2);
11
+ } while (x.length);
12
+ return ret;
13
+}
14
+
15
+```
16
+
17
+## Code
18
+
19
+```javascript
20
+function Component() {
21
+ const $ = React.unstable_useMemoCache(1);
22
+ let ret;
23
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
24
+ const x = [1, 2, 3];
25
+ ret = [];
26
+ do {
27
+ const item = x.pop();
28
+ ret.push(item * 2);
29
+ } while (x.length);
30
+ $[0] = ret;
31
+ } else {
32
+ ret = $[0];
33
+ }
34
+ return ret;
35
+}
36
+
37
+```
38
+
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/hir/do-while-simple.js
new
+9
@@ -0,0 +1,9 @@
1
+function Component() {
2
+ let x = [1, 2, 3];
3
+ let ret = [];
4
+ do {
5
+ let item = x.pop();
6
+ ret.push(item * 2);
7
+ } while (x.length);
8
+ return ret;
9
+}
compiler/forget/src/__tests__/fixtures/hir/error.todo-kitchensink.expect.md
+52
-63
@@ -50,8 +50,6 @@ function foo([a, b], { c, d, e = "e" }, f = "f", ...args) {
50
for (let x in { a: 1 }) {
51
}
52
53
- do {} while (i < 3);
54
-
53
let updateIdentifier = 0;
54
--updateIdentifier;
55
++updateIdentifier;
@@ -333,97 +331,88 @@ let moduleLocal = false;
331
| ^
332
47 | }
333
48 |
336
- 49 | do {} while (i < 3);
337
-
338
-[ReactForget] TodoError: (BuildHIR::lowerStatement) Handle DoWhileStatement statements
339
- 47 | }
340
- 48 |
341
-> 49 | do {} while (i < 3);
342
- | ^^^^^^^^^^^^^^^^^^^^
343
- 50 |
344
- 51 | let updateIdentifier = 0;
345
- 52 | --updateIdentifier;
334
+ 49 | let updateIdentifier = 0;
335
336
[ReactForget] TodoError: (BuildHIR::lowerExpression) Handle prefix UpdateExpression
348
- 50 |
349
- 51 | let updateIdentifier = 0;
350
-> 52 | --updateIdentifier;
337
+ 48 |
338
+ 49 | let updateIdentifier = 0;
339
+> 50 | --updateIdentifier;
340
| ^^^^^^^^^^^^^^^^^^
352
- 53 | ++updateIdentifier;
353
- 54 | updateIdentifier.y++;
354
- 55 | updateIdentifier.y--;
341
+ 51 | ++updateIdentifier;
342
+ 52 | updateIdentifier.y++;
343
+ 53 | updateIdentifier.y--;
344
345
[ReactForget] TodoError: (BuildHIR::lowerExpression) Handle prefix UpdateExpression
357
- 51 | let updateIdentifier = 0;
358
- 52 | --updateIdentifier;
359
-> 53 | ++updateIdentifier;
346
+ 49 | let updateIdentifier = 0;
347
+ 50 | --updateIdentifier;
348
+> 51 | ++updateIdentifier;
349
| ^^^^^^^^^^^^^^^^^^
361
- 54 | updateIdentifier.y++;
362
- 55 | updateIdentifier.y--;
363
- 56 |
350
+ 52 | updateIdentifier.y++;
351
+ 53 | updateIdentifier.y--;
352
+ 54 |
353
354
[ReactForget] TodoError: (BuildHIR::lowerExpression) Handle UpdateExpression with MemberExpression argument
366
- 52 | --updateIdentifier;
367
- 53 | ++updateIdentifier;
368
-> 54 | updateIdentifier.y++;
355
+ 50 | --updateIdentifier;
356
+ 51 | ++updateIdentifier;
357
+> 52 | updateIdentifier.y++;
358
| ^^^^^^^^^^^^^^^^^^^^
370
- 55 | updateIdentifier.y--;
371
- 56 |
372
- 57 | switch (i) {
359
+ 53 | updateIdentifier.y--;
360
+ 54 |
361
+ 55 | switch (i) {
362
363
[ReactForget] TodoError: (BuildHIR::lowerExpression) Handle UpdateExpression with MemberExpression argument
375
- 53 | ++updateIdentifier;
376
- 54 | updateIdentifier.y++;
377
-> 55 | updateIdentifier.y--;
364
+ 51 | ++updateIdentifier;
365
+ 52 | updateIdentifier.y++;
366
+> 53 | updateIdentifier.y--;
367
| ^^^^^^^^^^^^^^^^^^^^
379
- 56 |
380
- 57 | switch (i) {
381
- 58 | case 1 + 1: {
368
+ 54 |
369
+ 55 | switch (i) {
370
+ 56 | case 1 + 1: {
371
372
[ReactForget] TodoError: (BuildHIR::lowerStatement) Switch case test values must be identifiers or primitives, compound values are not yet supported
384
- 60 | case foo(): {
385
- 61 | }
386
-> 62 | case x.y: {
373
+ 58 | case foo(): {
374
+ 59 | }
375
+> 60 | case x.y: {
376
| ^^^
377
+ 61 | }
378
+ 62 | default: {
379
63 | }
389
- 64 | default: {
390
- 65 | }
380
381
[ReactForget] TodoError: (BuildHIR::lowerStatement) Switch case test values must be identifiers or primitives, compound values are not yet supported
393
- 58 | case 1 + 1: {
394
- 59 | }
395
-> 60 | case foo(): {
382
+ 56 | case 1 + 1: {
383
+ 57 | }
384
+> 58 | case foo(): {
385
| ^^^^^
386
+ 59 | }
387
+ 60 | case x.y: {
388
61 | }
398
- 62 | case x.y: {
399
- 63 | }
389
390
[ReactForget] TodoError: (BuildHIR::lowerStatement) Switch case test values must be identifiers or primitives, compound values are not yet supported
402
- 56 |
403
- 57 | switch (i) {
404
-> 58 | case 1 + 1: {
391
+ 54 |
392
+ 55 | switch (i) {
393
+> 56 | case 1 + 1: {
394
| ^^^^^
395
+ 57 | }
396
+ 58 | case foo(): {
397
59 | }
407
- 60 | case foo(): {
408
- 61 | }
398
399
[ReactForget] InvalidInputError: (BuildHIR::lowerAssignment) Assigning to an identifier defined outside the function scope is not supported.
411
- 67 |
412
- 68 | // Cannot assign to globals
413
-> 69 | someUnknownGlobal = true;
400
+ 65 |
401
+ 66 | // Cannot assign to globals
402
+> 67 | someUnknownGlobal = true;
403
| ^^^^^^^^^^^^^^^^^
415
- 70 | moduleLocal = true;
416
- 71 | }
417
- 72 |
404
+ 68 | moduleLocal = true;
405
+ 69 | }
406
+ 70 |
407
408
[ReactForget] InvalidInputError: (BuildHIR::lowerAssignment) Assigning to an identifier defined outside the function scope is not supported.
420
- 68 | // Cannot assign to globals
421
- 69 | someUnknownGlobal = true;
422
-> 70 | moduleLocal = true;
409
+ 66 | // Cannot assign to globals
410
+ 67 | someUnknownGlobal = true;
411
+> 68 | moduleLocal = true;
412
| ^^^^^^^^^^^
424
- 71 | }
425
- 72 |
426
- 73 | let moduleLocal = false;
413
+ 69 | }
414
+ 70 |
415
+ 71 | let moduleLocal = false;
416
```
417
418
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/hir/error.todo-kitchensink.js
-2
@@ -46,8 +46,6 @@ function foo([a, b], { c, d, e = "e" }, f = "f", ...args) {
46
for (let x in { a: 1 }) {
47
}
48
49
- do {} while (i < 3);
50
-
49
let updateIdentifier = 0;
50
--updateIdentifier;
51
++updateIdentifier;