From 58cfaf20eede72fde8f9b3a1edf5afb4694ce8ed Mon Sep 17 00:00:00 2001 From: Brian Ng Date: Tue, 7 Jul 2020 17:38:11 -0500 Subject: [PATCH] Fix break/continue when switch is nested inside loop (#11802) * Fix break/continue when switch is nested inside loop * merge retCheck --- .../src/index.js | 51 ++++--------------- .../for-break-continue-closure/exec.js | 15 ++++++ .../for-break-continue-closure/input.js | 13 +++++ .../for-break-continue-closure/output.js | 25 +++++++++ .../for-break-continue-return/output.js | 19 +++---- .../fixtures/general/superswitch/output.js | 9 +--- 6 files changed, 72 insertions(+), 60 deletions(-) create mode 100644 packages/babel-plugin-transform-block-scoping/test/fixtures/general/for-break-continue-closure/exec.js create mode 100644 packages/babel-plugin-transform-block-scoping/test/fixtures/general/for-break-continue-closure/input.js create mode 100644 packages/babel-plugin-transform-block-scoping/test/fixtures/general/for-break-continue-closure/output.js diff --git a/packages/babel-plugin-transform-block-scoping/src/index.js b/packages/babel-plugin-transform-block-scoping/src/index.js index 78ef881b71cb..4ba70bcb670a 100644 --- a/packages/babel-plugin-transform-block-scoping/src/index.js +++ b/packages/babel-plugin-transform-block-scoping/src/index.js @@ -844,55 +844,26 @@ class BlockScoping { buildHas(ret: string) { const body = this.body; - - let retCheck; const has = this.has; - const cases = []; - - if (has.hasReturn) { - // typeof ret === "object" - retCheck = buildRetCheck({ - RETURN: t.identifier(ret), - }); - } if (has.hasBreakContinue) { for (const key of Object.keys(has.map)) { - cases.push(t.switchCase(t.stringLiteral(key), [has.map[key]])); - } - - if (has.hasReturn) { - cases.push(t.switchCase(null, [retCheck])); - } - - if (cases.length === 1) { - const single = cases[0]; body.push( t.ifStatement( - t.binaryExpression("===", t.identifier(ret), single.test), - single.consequent[0], + t.binaryExpression("===", t.identifier(ret), t.stringLiteral(key)), + has.map[key], ), ); - } else { - if (this.loop) { - // https://github.com/babel/babel/issues/998 - for (let i = 0; i < cases.length; i++) { - const caseConsequent = cases[i].consequent[0]; - if (t.isBreakStatement(caseConsequent) && !caseConsequent.label) { - if (!this.loopLabel) { - this.loopLabel = this.scope.generateUidIdentifier("loop"); - } - caseConsequent.label = t.cloneNode(this.loopLabel); - } - } - } - - body.push(t.switchStatement(t.identifier(ret), cases)); - } - } else { - if (has.hasReturn) { - body.push(retCheck); } } + + // typeof ret === "object" + if (has.hasReturn) { + body.push( + buildRetCheck({ + RETURN: t.identifier(ret), + }), + ); + } } } diff --git a/packages/babel-plugin-transform-block-scoping/test/fixtures/general/for-break-continue-closure/exec.js b/packages/babel-plugin-transform-block-scoping/test/fixtures/general/for-break-continue-closure/exec.js new file mode 100644 index 000000000000..4ee56e9409d7 --- /dev/null +++ b/packages/babel-plugin-transform-block-scoping/test/fixtures/general/for-break-continue-closure/exec.js @@ -0,0 +1,15 @@ +expect(() => { + for (const a of [1]) { + switch (true) { + case true: { + const b = 1; + () => b; + if (true) break; + continue; + } + case false: { + throw new Error("unreachable"); + } + } + } +}).not.toThrow(); diff --git a/packages/babel-plugin-transform-block-scoping/test/fixtures/general/for-break-continue-closure/input.js b/packages/babel-plugin-transform-block-scoping/test/fixtures/general/for-break-continue-closure/input.js new file mode 100644 index 000000000000..98cd9d4a488f --- /dev/null +++ b/packages/babel-plugin-transform-block-scoping/test/fixtures/general/for-break-continue-closure/input.js @@ -0,0 +1,13 @@ +for (const a of [1]) { + switch (true) { + case true: { + const b = 1; + () => b; + if (true) break; + continue; + } + case false: { + throw new Error("unreachable"); + } + } +} diff --git a/packages/babel-plugin-transform-block-scoping/test/fixtures/general/for-break-continue-closure/output.js b/packages/babel-plugin-transform-block-scoping/test/fixtures/general/for-break-continue-closure/output.js new file mode 100644 index 000000000000..f39eb1b3642f --- /dev/null +++ b/packages/babel-plugin-transform-block-scoping/test/fixtures/general/for-break-continue-closure/output.js @@ -0,0 +1,25 @@ +for (var a of [1]) { + switch (true) { + case true: + { + var _ret = function () { + var b = 1; + + (function () { + return b; + }); + + if (true) return "break"; + return "continue"; + }(); + + if (_ret === "break") break; + if (_ret === "continue") continue; + } + + case false: + { + throw new Error("unreachable"); + } + } +} diff --git a/packages/babel-plugin-transform-block-scoping/test/fixtures/general/for-break-continue-return/output.js b/packages/babel-plugin-transform-block-scoping/test/fixtures/general/for-break-continue-return/output.js index 765124078779..c73fecc8943b 100644 --- a/packages/babel-plugin-transform-block-scoping/test/fixtures/general/for-break-continue-return/output.js +++ b/packages/babel-plugin-transform-block-scoping/test/fixtures/general/for-break-continue-return/output.js @@ -1,5 +1,5 @@ (function () { - var _loop2 = function (i) { + var _loop = function (i) { fns.push(function () { return i; }); @@ -15,18 +15,11 @@ } }; - _loop: for (var i in nums) { - var _ret = _loop2(i); + for (var i in nums) { + var _ret = _loop(i); - switch (_ret) { - case "continue": - continue; - - case "break": - break _loop; - - default: - if (typeof _ret === "object") return _ret.v; - } + if (_ret === "continue") continue; + if (_ret === "break") break; + if (typeof _ret === "object") return _ret.v; } })(); diff --git a/packages/babel-plugin-transform-block-scoping/test/fixtures/general/superswitch/output.js b/packages/babel-plugin-transform-block-scoping/test/fixtures/general/superswitch/output.js index 80b21eba9cdc..4fa75b17916e 100644 --- a/packages/babel-plugin-transform-block-scoping/test/fixtures/general/superswitch/output.js +++ b/packages/babel-plugin-transform-block-scoping/test/fixtures/general/superswitch/output.js @@ -18,13 +18,8 @@ function foo() { return "break"; }(); - switch (_ret) { - case "break": - break; - - default: - if (typeof _ret === "object") return _ret.v; - } + if (_ret === "break") break; + if (typeof _ret === "object") return _ret.v; } } }