From 387cda8fbbaa5a6bd1f1496381752f0f35676554 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=B2=20Ribaudo?= Date: Tue, 12 Jun 2018 19:40:52 +0200 Subject: [PATCH] isConstantExpression should return true for immuable bindings (#8122) * isConstantExpression should return true for immuable bindings * New test * Don't return undefined --- .../src/index.js | 9 +++++---- .../fixtures/public-loose/computed/output.js | 3 +-- .../test/fixtures/public/computed/output.js | 3 +-- .../test/fixtures/regression/8110/input.js | 5 +++++ .../test/fixtures/regression/8110/options.json | 3 +++ .../test/fixtures/regression/8110/output.js | 8 ++++++++ .../options.json | 5 ----- .../static-property-tdz-general/exec.js | 3 --- .../static-property-tdz-general/options.json | 5 ----- .../fixtures/static-property-tdz-loose/exec.js | 3 --- .../static-property-tdz-loose/options.json | 5 ----- .../static-property-tdz/edgest-case/exec.js | 5 +++++ .../edgest-case}/input.js | 0 .../edgest-case/options.json | 3 +++ .../static-property-tdz/edgest-case/output.js | 17 +++++++++++++++++ .../static-property-tdz/general/exec.js | 5 +++++ .../general}/input.js | 0 .../static-property-tdz/general/options.json | 3 +++ .../static-property-tdz/general/output.js | 15 +++++++++++++++ .../fixtures/static-property-tdz/loose/exec.js | 5 +++++ .../loose}/input.js | 0 .../static-property-tdz/loose/options.json | 3 +++ .../static-property-tdz/loose/output.js | 7 +++++++ .../babel-traverse/src/path/introspection.js | 6 ++---- 24 files changed, 88 insertions(+), 33 deletions(-) create mode 100644 packages/babel-plugin-proposal-class-properties/test/fixtures/regression/8110/input.js create mode 100644 packages/babel-plugin-proposal-class-properties/test/fixtures/regression/8110/options.json create mode 100644 packages/babel-plugin-proposal-class-properties/test/fixtures/regression/8110/output.js delete mode 100644 packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz-edgest-case/options.json delete mode 100644 packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz-general/exec.js delete mode 100644 packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz-general/options.json delete mode 100644 packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz-loose/exec.js delete mode 100644 packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz-loose/options.json create mode 100644 packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz/edgest-case/exec.js rename packages/babel-plugin-proposal-class-properties/test/fixtures/{static-property-tdz-edgest-case => static-property-tdz/edgest-case}/input.js (100%) create mode 100644 packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz/edgest-case/options.json create mode 100644 packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz/edgest-case/output.js create mode 100644 packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz/general/exec.js rename packages/babel-plugin-proposal-class-properties/test/fixtures/{static-property-tdz-general => static-property-tdz/general}/input.js (100%) create mode 100644 packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz/general/options.json create mode 100644 packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz/general/output.js create mode 100644 packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz/loose/exec.js rename packages/babel-plugin-proposal-class-properties/test/fixtures/{static-property-tdz-loose => static-property-tdz/loose}/input.js (100%) create mode 100644 packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz/loose/options.json create mode 100644 packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz/loose/output.js diff --git a/packages/babel-plugin-proposal-class-properties/src/index.js b/packages/babel-plugin-proposal-class-properties/src/index.js index c60e4c63e4..d3c833c5e5 100644 --- a/packages/babel-plugin-proposal-class-properties/src/index.js +++ b/packages/babel-plugin-proposal-class-properties/src/index.js @@ -319,14 +319,15 @@ export default declare((api, options) => { const instanceBody = []; for (const computedPath of computedPaths) { + computedPath.traverse(classFieldDefinitionEvaluationTDZVisitor, { + classRef: path.scope.getBinding(ref.name), + file: this.file, + }); + const computedNode = computedPath.node; // Make sure computed property names are only evaluated once (upon class definition) // and in the right order in combination with static properties if (!computedPath.get("key").isConstantExpression()) { - computedPath.traverse(classFieldDefinitionEvaluationTDZVisitor, { - classRef: path.scope.getBinding(ref.name), - file: this.file, - }); const ident = path.scope.generateUidIdentifierBasedOnNode( computedNode.key, ); diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/public-loose/computed/output.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/public-loose/computed/output.js index 9389374c65..0cd7c14b45 100644 --- a/packages/babel-plugin-proposal-class-properties/test/fixtures/public-loose/computed/output.js +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/public-loose/computed/output.js @@ -17,7 +17,6 @@ var _computed2 = computed(); var _ref2 = "test" + one; var _ref3 = /regex/; -var _bar = bar; var _baz = baz; var _ref4 = `template${expression}`; @@ -33,7 +32,7 @@ function () { this[void 0] = "void 0"; this[_ref3] = "regex"; this[foo] = "foo"; - this[_bar] = "bar"; + this[bar] = "bar"; this[_baz] = "baz"; this[`template`] = "template"; this[_ref4] = "template-with-expression"; diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/public/computed/output.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/public/computed/output.js index 1f50eda352..bc9a90b212 100644 --- a/packages/babel-plugin-proposal-class-properties/test/fixtures/public/computed/output.js +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/public/computed/output.js @@ -17,7 +17,6 @@ var _computed2 = computed(); var _ref2 = "test" + one; var _ref3 = /regex/; -var _bar = bar; var _baz = baz; var _ref4 = `template${expression}`; @@ -33,7 +32,7 @@ function () { babelHelpers.defineProperty(this, void 0, "void 0"); babelHelpers.defineProperty(this, _ref3, "regex"); babelHelpers.defineProperty(this, foo, "foo"); - babelHelpers.defineProperty(this, _bar, "bar"); + babelHelpers.defineProperty(this, bar, "bar"); babelHelpers.defineProperty(this, _baz, "baz"); babelHelpers.defineProperty(this, `template`, "template"); babelHelpers.defineProperty(this, _ref4, "template-with-expression"); diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/regression/8110/input.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/regression/8110/input.js new file mode 100644 index 0000000000..d5fd1856b9 --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/regression/8110/input.js @@ -0,0 +1,5 @@ +const field = Symbol('field'); + +class A { + [field] = 10; +} diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/regression/8110/options.json b/packages/babel-plugin-proposal-class-properties/test/fixtures/regression/8110/options.json new file mode 100644 index 0000000000..9d30185b9b --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/regression/8110/options.json @@ -0,0 +1,3 @@ +{ + "plugins": ["external-helpers", "proposal-class-properties"] +} diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/regression/8110/output.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/regression/8110/output.js new file mode 100644 index 0000000000..b5d524b432 --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/regression/8110/output.js @@ -0,0 +1,8 @@ +const field = Symbol('field'); + +class A { + constructor() { + babelHelpers.defineProperty(this, field, 10); + } + +} diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz-edgest-case/options.json b/packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz-edgest-case/options.json deleted file mode 100644 index 7077bdfea3..0000000000 --- a/packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz-edgest-case/options.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "plugins": ["proposal-class-properties", "transform-classes"], - "minNodeVersion": "6.0.0", - "throws": "Class \"A\" cannot be referenced in computed property keys." -} diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz-general/exec.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz-general/exec.js deleted file mode 100644 index 907262b4a5..0000000000 --- a/packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz-general/exec.js +++ /dev/null @@ -1,3 +0,0 @@ -class C { - static [C + 3] = 3; -} diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz-general/options.json b/packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz-general/options.json deleted file mode 100644 index 265ff32439..0000000000 --- a/packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz-general/options.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "plugins": ["proposal-class-properties", "transform-classes"], - "minNodeVersion": "6.0.0", - "throws": "Class \"C\" cannot be referenced in computed property keys." -} diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz-loose/exec.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz-loose/exec.js deleted file mode 100644 index 907262b4a5..0000000000 --- a/packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz-loose/exec.js +++ /dev/null @@ -1,3 +0,0 @@ -class C { - static [C + 3] = 3; -} diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz-loose/options.json b/packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz-loose/options.json deleted file mode 100644 index dde6ad6780..0000000000 --- a/packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz-loose/options.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "plugins": [["proposal-class-properties", {"loose": true}]], - "minNodeVersion": "6.0.0", - "throws": "Class \"C\" cannot be referenced in computed property keys." -} diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz/edgest-case/exec.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz/edgest-case/exec.js new file mode 100644 index 0000000000..29f56228fe --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz/edgest-case/exec.js @@ -0,0 +1,5 @@ +expect(() => { + class A { + static [{ x: A || 0 }.x]; + } +}).toThrow(); diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz-edgest-case/input.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz/edgest-case/input.js similarity index 100% rename from packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz-edgest-case/input.js rename to packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz/edgest-case/input.js diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz/edgest-case/options.json b/packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz/edgest-case/options.json new file mode 100644 index 0000000000..4db9330e8b --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz/edgest-case/options.json @@ -0,0 +1,3 @@ +{ + "plugins": ["proposal-class-properties", "transform-classes"] +} diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz/edgest-case/output.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz/edgest-case/output.js new file mode 100644 index 0000000000..c3fc9ecd57 --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz/edgest-case/output.js @@ -0,0 +1,17 @@ +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } + +function _classNameTDZError(name) { throw new Error("Class \"" + name + "\" cannot be referenced in computed property keys."); } + +var _x$x = { + x: (_classNameTDZError("A"), A) || 0 +}.x; + +let A = function A() { + "use strict"; + + _classCallCheck(this, A); +}; + +_defineProperty(A, _x$x, void 0); diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz/general/exec.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz/general/exec.js new file mode 100644 index 0000000000..2c167f59f8 --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz/general/exec.js @@ -0,0 +1,5 @@ +expect(() => { + class C { + static [C + 3] = 3; + } +}).toThrow(); diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz-general/input.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz/general/input.js similarity index 100% rename from packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz-general/input.js rename to packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz/general/input.js diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz/general/options.json b/packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz/general/options.json new file mode 100644 index 0000000000..4db9330e8b --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz/general/options.json @@ -0,0 +1,3 @@ +{ + "plugins": ["proposal-class-properties", "transform-classes"] +} diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz/general/output.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz/general/output.js new file mode 100644 index 0000000000..21c823a89a --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz/general/output.js @@ -0,0 +1,15 @@ +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } + +function _classNameTDZError(name) { throw new Error("Class \"" + name + "\" cannot be referenced in computed property keys."); } + +var _ref = (_classNameTDZError("C"), C) + 3; + +let C = function C() { + "use strict"; + + _classCallCheck(this, C); +}; + +_defineProperty(C, _ref, 3); diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz/loose/exec.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz/loose/exec.js new file mode 100644 index 0000000000..2c167f59f8 --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz/loose/exec.js @@ -0,0 +1,5 @@ +expect(() => { + class C { + static [C + 3] = 3; + } +}).toThrow(); diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz-loose/input.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz/loose/input.js similarity index 100% rename from packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz-loose/input.js rename to packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz/loose/input.js diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz/loose/options.json b/packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz/loose/options.json new file mode 100644 index 0000000000..693db86a79 --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz/loose/options.json @@ -0,0 +1,3 @@ +{ + "plugins": [["proposal-class-properties", { "loose": true }]] +} diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz/loose/output.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz/loose/output.js new file mode 100644 index 0000000000..a6acc92159 --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz/loose/output.js @@ -0,0 +1,7 @@ +function _classNameTDZError(name) { throw new Error("Class \"" + name + "\" cannot be referenced in computed property keys."); } + +var _ref = (_classNameTDZError("C"), C) + 3; + +class C {} + +C[_ref] = 3; diff --git a/packages/babel-traverse/src/path/introspection.js b/packages/babel-traverse/src/path/introspection.js index 2ab558d5aa..078fee3740 100644 --- a/packages/babel-traverse/src/path/introspection.js +++ b/packages/babel-traverse/src/path/introspection.js @@ -402,10 +402,8 @@ export function _resolve(dangerous?, resolved?): ?NodePath { export function isConstantExpression() { if (this.isIdentifier()) { const binding = this.scope.getBinding(this.node.name); - if (!binding) { - return false; - } - return binding.constant && binding.path.get("init").isConstantExpression(); + if (!binding) return false; + return binding.constant; } if (this.isLiteral()) {