From 95c93dd22b7d2475a7bc4f90554c96e7bd2ad204 Mon Sep 17 00:00:00 2001 From: Amjad Masad Date: Sun, 17 Jan 2016 13:19:37 -0800 Subject: [PATCH] Method names should not be bound to body As an artificat of compiling methods to named function expressions the function name is being considered a "local" binding in the function body. This means that we will throw errors anytime someone would want to create a new local binding with the same name. This is solved by assigning a symbol to function Identifiers that indicates that they should not be considered local bindings. --- packages/babel-helper-define-map/src/index.js | 5 +++++ .../test/fixtures/regression/T6712/actual.js | 5 +++++ .../test/fixtures/regression/T6712/expected.js | 15 +++++++++++++++ packages/babel-traverse/src/scope/index.js | 8 ++++++-- packages/babel-types/src/constants.js | 1 + 5 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 packages/babel-plugin-transform-es2015-classes/test/fixtures/regression/T6712/actual.js create mode 100644 packages/babel-plugin-transform-es2015-classes/test/fixtures/regression/T6712/expected.js diff --git a/packages/babel-helper-define-map/src/index.js b/packages/babel-helper-define-map/src/index.js index 43c5c5a1c2..0cc8e78f56 100644 --- a/packages/babel-helper-define-map/src/index.js +++ b/packages/babel-helper-define-map/src/index.js @@ -63,6 +63,11 @@ export function push(mutatorMap: Object, node: Object, kind: string, file, scope // infer function name if (scope && t.isStringLiteral(key) && (kind === "value" || kind === "initializer") && t.isFunctionExpression(value)) { value = nameFunction({ id: key, node: value, scope }); + + // Class methods don't have their name bound in the funciton body. + if (t.isClassMethod(node)) { + value.id[t.NOT_LOCAL_BINDING] = true + } } if (value) { diff --git a/packages/babel-plugin-transform-es2015-classes/test/fixtures/regression/T6712/actual.js b/packages/babel-plugin-transform-es2015-classes/test/fixtures/regression/T6712/actual.js new file mode 100644 index 0000000000..0fd86891e6 --- /dev/null +++ b/packages/babel-plugin-transform-es2015-classes/test/fixtures/regression/T6712/actual.js @@ -0,0 +1,5 @@ +class A { + foo() { + const foo = 2; + } +} diff --git a/packages/babel-plugin-transform-es2015-classes/test/fixtures/regression/T6712/expected.js b/packages/babel-plugin-transform-es2015-classes/test/fixtures/regression/T6712/expected.js new file mode 100644 index 0000000000..1a2650f95e --- /dev/null +++ b/packages/babel-plugin-transform-es2015-classes/test/fixtures/regression/T6712/expected.js @@ -0,0 +1,15 @@ +"use strict"; + +var A = function () { + function A() { + babelHelpers.classCallCheck(this, A); + } + + babelHelpers.createClass(A, [{ + key: "foo", + value: function foo() { + var foo = 2; + } + }]); + return A; +}(); diff --git a/packages/babel-traverse/src/scope/index.js b/packages/babel-traverse/src/scope/index.js index 747fbca3d3..80a11db083 100644 --- a/packages/babel-traverse/src/scope/index.js +++ b/packages/babel-traverse/src/scope/index.js @@ -663,13 +663,17 @@ export default class Scope { // FunctionExpression - id if (path.isFunctionExpression() && path.has("id")) { - this.registerBinding("local", path.get("id"), path); + if (!path.get("id").node[t.NOT_LOCAL_BINDING]) { + this.registerBinding("local", path.get("id"), path); + } } // Class if (path.isClassExpression() && path.has("id")) { - this.registerBinding("local", path); + if (!path.get("id").node[t.NOT_LOCAL_BINDING]) { + this.registerBinding("local", path); + } } // Function - params, rest diff --git a/packages/babel-types/src/constants.js b/packages/babel-types/src/constants.js index 179ccded3e..78dca8a2d8 100644 --- a/packages/babel-types/src/constants.js +++ b/packages/babel-types/src/constants.js @@ -24,3 +24,4 @@ export const INHERIT_KEYS = { }; export const BLOCK_SCOPED_SYMBOL = Symbol.for("var used to be block scoped"); +export const NOT_LOCAL_BINDING = Symbol.for("should not be considered a local binding");