From 7a7538920eee213e70351d467e514b4e7be637a9 Mon Sep 17 00:00:00 2001 From: Joe Savona Date: Mon, 9 Jan 2023 13:04:30 -0800 Subject: [PATCH] Broken test for labeled statements When we convert a LabeledStatement to HIR we can end up emitting "consecutive" blocks, ie where there are two blocks such that control flow will always go from from one block to the other, with no other way to reach the second block but through the first. Example: ```javascript label: { foo(); break label; } bar(); ``` Converts to ``` bb0: foo() goto bb1: bb1: bar(); ... ``` Ideally in this case we would merge these into a single block: * When debugging, the extra goto makes it look like there is conditional control flow when there isn't. If the code is consecutive it's easier to understand that if it's a single block. * Conversion from HIR -> AST relies on consecutive code all being in a single block, so this breaks codegen (we never visit the goto target since all gotos are assumed to be safe to convert to a break or continue). This PR adds a failing test case, the next PR fixes it. --- .../fixtures/hir/inverted-if.expect.md | 26 ++++++++++++++++--- .../src/__tests__/fixtures/hir/inverted-if.js | 1 + .../hir/unconditional-break-label.expect.md | 25 ++++++++++++++++++ .../fixtures/hir/unconditional-break-label.js | 8 ++++++ 4 files changed, 56 insertions(+), 4 deletions(-) create mode 100644 compiler/forget/src/__tests__/fixtures/hir/unconditional-break-label.expect.md create mode 100644 compiler/forget/src/__tests__/fixtures/hir/unconditional-break-label.js diff --git a/compiler/forget/src/__tests__/fixtures/hir/inverted-if.expect.md b/compiler/forget/src/__tests__/fixtures/hir/inverted-if.expect.md index 3c2d2c06fa..62bbd1a2f0 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/inverted-if.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/inverted-if.expect.md @@ -10,6 +10,7 @@ function foo(a, b, c) { break label; } } + return y; } ``` @@ -18,12 +19,29 @@ function foo(a, b, c) { ```javascript function foo(a, b, c) { - const y = []; - if (a) { - if (b) { - y.push(c); + const $ = React.useMemoCache(); + const c_0 = $[0] !== a; + const c_1 = $[1] !== b; + const c_2 = $[2] !== c; + let y; + if (c_0 || c_1 || c_2) { + y = []; + + if (a) { + if (b) { + y.push(c); + } } + + $[0] = a; + $[1] = b; + $[2] = c; + $[3] = y; + } else { + y = $[3]; } + + return y; } ``` diff --git a/compiler/forget/src/__tests__/fixtures/hir/inverted-if.js b/compiler/forget/src/__tests__/fixtures/hir/inverted-if.js index c52ec745cf..0555787fce 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/inverted-if.js +++ b/compiler/forget/src/__tests__/fixtures/hir/inverted-if.js @@ -6,4 +6,5 @@ function foo(a, b, c) { break label; } } + return y; } diff --git a/compiler/forget/src/__tests__/fixtures/hir/unconditional-break-label.expect.md b/compiler/forget/src/__tests__/fixtures/hir/unconditional-break-label.expect.md new file mode 100644 index 0000000000..e1bdf2882f --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/hir/unconditional-break-label.expect.md @@ -0,0 +1,25 @@ + +## Input + +```javascript +function foo(a) { + let x = 0; + bar: { + x = 1; + break bar; + } + return a + x; +} + +``` + +## Code + +```javascript +function foo(a) { + const x = 0; + const x$0 = 1; +} + +``` + \ No newline at end of file diff --git a/compiler/forget/src/__tests__/fixtures/hir/unconditional-break-label.js b/compiler/forget/src/__tests__/fixtures/hir/unconditional-break-label.js new file mode 100644 index 0000000000..26a932284c --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/hir/unconditional-break-label.js @@ -0,0 +1,8 @@ +function foo(a) { + let x = 0; + bar: { + x = 1; + break bar; + } + return a + x; +}