From bc1b9537b00499f462aa3ac0d49e30314a66f413 Mon Sep 17 00:00:00 2001 From: Nitin Kumar Date: Tue, 6 Jul 2021 23:29:24 +0530 Subject: [PATCH] Fix arrow transformation when `arguments` is defined as variable (#12344) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: arrow-fn transformation when 'arguments' is defined as var * fix: tests * refactor: code * Review by @nicolo-ribaudo Co-authored-by: Nicolò Ribaudo --- .../arguments-global-undeclared/input.js | 9 ++++ .../arguments-global-undeclared/output.js | 19 +++++++ .../arguments-global-var/input.js | 10 ++++ .../arguments-global-var/output.js | 19 +++++++ .../arrow-functions/arguments/input.js | 36 +++++++++++++ .../arrow-functions/arguments/output.js | 53 +++++++++++++++++++ .../babel-traverse/src/path/conversion.ts | 30 +++++++++-- 7 files changed, 173 insertions(+), 3 deletions(-) create mode 100644 packages/babel-plugin-transform-arrow-functions/test/fixtures/arrow-functions/arguments-global-undeclared/input.js create mode 100644 packages/babel-plugin-transform-arrow-functions/test/fixtures/arrow-functions/arguments-global-undeclared/output.js create mode 100644 packages/babel-plugin-transform-arrow-functions/test/fixtures/arrow-functions/arguments-global-var/input.js create mode 100644 packages/babel-plugin-transform-arrow-functions/test/fixtures/arrow-functions/arguments-global-var/output.js diff --git a/packages/babel-plugin-transform-arrow-functions/test/fixtures/arrow-functions/arguments-global-undeclared/input.js b/packages/babel-plugin-transform-arrow-functions/test/fixtures/arrow-functions/arguments-global-undeclared/input.js new file mode 100644 index 0000000000..42903d8904 --- /dev/null +++ b/packages/babel-plugin-transform-arrow-functions/test/fixtures/arrow-functions/arguments-global-undeclared/input.js @@ -0,0 +1,9 @@ +function fn() { + var foo = () => { + return arguments; + }; +} + +var bar = () => arguments; + +var baz = () => () => arguments; diff --git a/packages/babel-plugin-transform-arrow-functions/test/fixtures/arrow-functions/arguments-global-undeclared/output.js b/packages/babel-plugin-transform-arrow-functions/test/fixtures/arrow-functions/arguments-global-undeclared/output.js new file mode 100644 index 0000000000..7b04621652 --- /dev/null +++ b/packages/babel-plugin-transform-arrow-functions/test/fixtures/arrow-functions/arguments-global-undeclared/output.js @@ -0,0 +1,19 @@ +var _arguments2 = typeof arguments === "undefined" ? void 0 : arguments; + +function fn() { + var _arguments = arguments; + + var foo = function () { + return _arguments; + }; +} + +var bar = function () { + return _arguments2; +}; + +var baz = function () { + return function () { + return _arguments2; + }; +}; diff --git a/packages/babel-plugin-transform-arrow-functions/test/fixtures/arrow-functions/arguments-global-var/input.js b/packages/babel-plugin-transform-arrow-functions/test/fixtures/arrow-functions/arguments-global-var/input.js new file mode 100644 index 0000000000..5f7d9826d3 --- /dev/null +++ b/packages/babel-plugin-transform-arrow-functions/test/fixtures/arrow-functions/arguments-global-var/input.js @@ -0,0 +1,10 @@ +var arguments = 1; +function fn() { + var foo = () => { + return arguments; + }; +} + +var bar = () => arguments; + +var baz = () => () => arguments; diff --git a/packages/babel-plugin-transform-arrow-functions/test/fixtures/arrow-functions/arguments-global-var/output.js b/packages/babel-plugin-transform-arrow-functions/test/fixtures/arrow-functions/arguments-global-var/output.js new file mode 100644 index 0000000000..f19432c825 --- /dev/null +++ b/packages/babel-plugin-transform-arrow-functions/test/fixtures/arrow-functions/arguments-global-var/output.js @@ -0,0 +1,19 @@ +var _arguments2 = 1; + +function fn() { + var _arguments = _arguments2; + + var foo = function () { + return _arguments; + }; +} + +var bar = function () { + return _arguments2; +}; + +var baz = function () { + return function () { + return _arguments2; + }; +}; diff --git a/packages/babel-plugin-transform-arrow-functions/test/fixtures/arrow-functions/arguments/input.js b/packages/babel-plugin-transform-arrow-functions/test/fixtures/arrow-functions/arguments/input.js index 198ac999f6..5d9e7c9091 100644 --- a/packages/babel-plugin-transform-arrow-functions/test/fixtures/arrow-functions/arguments/input.js +++ b/packages/babel-plugin-transform-arrow-functions/test/fixtures/arrow-functions/arguments/input.js @@ -43,3 +43,39 @@ function six(obj) { return fn(); } six(); + +var seven = () => { + var arguments = 1; + return arguments; +}; +seven(); + +var eight = () => { + var arguments = 1; + return () => arguments; +}; +eight(); + +function nine() { + var arguments = 1; + var foo = () => { + return arguments; + }; +} +nine(); + +var eleven = () => { + var arguments = 2; + return function () { + return () => arguments; + } +}; +eleven()(1,2,3)(); + +var twelve = () => { + var arguments = 2; + return class { + m() { return () => arguments; } + } +}; +twelve(); diff --git a/packages/babel-plugin-transform-arrow-functions/test/fixtures/arrow-functions/arguments/output.js b/packages/babel-plugin-transform-arrow-functions/test/fixtures/arrow-functions/arguments/output.js index 84bbb58be4..9110a69ddc 100644 --- a/packages/babel-plugin-transform-arrow-functions/test/fixtures/arrow-functions/arguments/output.js +++ b/packages/babel-plugin-transform-arrow-functions/test/fixtures/arrow-functions/arguments/output.js @@ -81,3 +81,56 @@ function six(obj) { } six(); + +var seven = function () { + var _arguments6 = 1; + return _arguments6; +}; + +seven(); + +var eight = function () { + var _arguments7 = 1; + return function () { + return _arguments7; + }; +}; + +eight(); + +function nine() { + var _arguments8 = 1; + + var foo = function () { + return _arguments8; + }; +} + +nine(); + +var eleven = function () { + var arguments = 2; + return function () { + var _arguments9 = arguments; + return function () { + return _arguments9; + }; + }; +}; + +eleven()(1, 2, 3)(); + +var twelve = function () { + var arguments = 2; + return class { + m() { + var _arguments10 = arguments; + return function () { + return _arguments10; + }; + } + + }; +}; + +twelve(); diff --git a/packages/babel-traverse/src/path/conversion.ts b/packages/babel-traverse/src/path/conversion.ts index d92de9b7e9..484fcbba1d 100644 --- a/packages/babel-traverse/src/path/conversion.ts +++ b/packages/babel-traverse/src/path/conversion.ts @@ -226,9 +226,22 @@ function hoistFunctionEnvironment( // Convert all "arguments" references in the arrow to point at the alias. if (argumentsPaths.length > 0) { - const argumentsBinding = getBinding(thisEnvFn, "arguments", () => - t.identifier("arguments"), - ); + const argumentsBinding = getBinding(thisEnvFn, "arguments", () => { + const args = () => t.identifier("arguments"); + if (thisEnvFn.scope.path.isProgram()) { + return t.conditionalExpression( + t.binaryExpression( + "===", + t.unaryExpression("typeof", args()), + t.stringLiteral("undefined"), + ), + thisEnvFn.scope.buildUndefinedNode(), + args(), + ); + } else { + return args(); + } + }); argumentsPaths.forEach(argumentsChild => { const argsRef = t.identifier(argumentsBinding); @@ -583,6 +596,17 @@ function getScopeInformation(fnPath) { ReferencedIdentifier(child) { if (child.node.name !== "arguments") return; + let curr = child.scope; + do { + if (curr.hasOwnBinding("arguments")) { + curr.rename("arguments"); + return; + } + if (curr.path.isFunction() && !curr.path.isArrowFunctionExpression()) { + break; + } + } while ((curr = curr.parent)); + argumentsPaths.push(child); }, MetaProperty(child) {