@samitouri / QOS-React / commits / 440fd1f24a

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;