From ec69b4bb1256c061ac76f53dfed09c4283ec6a31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=B2=20Ribaudo?= Date: Fri, 27 Jul 2018 22:24:57 +0200 Subject: [PATCH] Save full descriptor instead of only value for private fields. (#8318) * Save full descriptor instead of only value for private fields. Decorators can make private fields non-writable, so we need to store this information somewhere. The descriptor can also be used to implement private accessors. --- packages/babel-helpers/src/helpers.js | 11 +++- .../src/index.js | 9 +++- .../fixtures/private/assignment/output.js | 5 +- .../test/fixtures/private/call/output.js | 7 ++- .../test/fixtures/private/canonical/output.js | 10 +++- .../private/constructor-collision/output.js | 5 +- .../private/declaration-order/output.js | 5 +- .../private/derived-multiple-supers/output.js | 10 +++- .../test/fixtures/private/derived/output.js | 10 +++- .../fixtures/private/extracted-this/output.js | 10 +++- .../test/fixtures/private/foobar/output.js | 7 ++- .../private/instance-undefined/output.js | 5 +- .../test/fixtures/private/instance/output.js | 5 +- .../test/fixtures/private/multiple/output.js | 10 +++- .../private/private-in-derived/output.js | 5 +- .../reference-in-other-property/output.js | 15 ++++-- .../private/regression-T7364/output.mjs | 51 +++++++++++++------ .../fixtures/private/super-call/output.js | 5 +- .../private/super-expression/output.js | 5 +- .../private/super-statement/output.js | 5 +- .../test/fixtures/private/update/output.js | 5 +- 21 files changed, 155 insertions(+), 45 deletions(-) diff --git a/packages/babel-helpers/src/helpers.js b/packages/babel-helpers/src/helpers.js index d25bdecb8e..842668c8d7 100644 --- a/packages/babel-helpers/src/helpers.js +++ b/packages/babel-helpers/src/helpers.js @@ -1016,7 +1016,7 @@ helpers.classPrivateFieldGet = () => template.program.ast` if (!privateMap.has(receiver)) { throw new TypeError("attempted to get private field on non-instance"); } - return privateMap.get(receiver); + return privateMap.get(receiver).value; } `; @@ -1025,7 +1025,14 @@ helpers.classPrivateFieldSet = () => template.program.ast` if (!privateMap.has(receiver)) { throw new TypeError("attempted to set private field on non-instance"); } - privateMap.set(receiver, value); + var descriptor = privateMap.get(receiver); + if (!descriptor.writable) { + // This should only throw in strict mode, but class bodies are + // always strict and private fields can only be used inside + // class bodies. + throw new TypeError("attempted to set read only private field"); + } + descriptor.value = value; return value; } `; diff --git a/packages/babel-plugin-proposal-class-properties/src/index.js b/packages/babel-plugin-proposal-class-properties/src/index.js index d3c833c5e5..5514ea7007 100644 --- a/packages/babel-plugin-proposal-class-properties/src/index.js +++ b/packages/babel-plugin-proposal-class-properties/src/index.js @@ -201,7 +201,14 @@ export default declare((api, options) => { // Must be late evaluated in case it references another private field. return () => - template.statement`MAP.set(REF, VALUE);`({ + template.statement` + MAP.set(REF, { + // configurable is always false for private elements + // enumerable is always false for private elements + writable: true, + value: VALUE + }); + `({ MAP: map, REF: ref, VALUE: path.node.value || scope.buildUndefinedNode(), diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/assignment/output.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/assignment/output.js index bf56ee4e34..09f9f0b622 100644 --- a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/assignment/output.js +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/assignment/output.js @@ -6,7 +6,10 @@ function () { function Foo() { babelHelpers.classCallCheck(this, Foo); - _foo.set(this, 0); + _foo.set(this, { + writable: true, + value: 0 + }); } babelHelpers.createClass(Foo, [{ diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/call/output.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/call/output.js index cc609c1f73..575d880c79 100644 --- a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/call/output.js +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/call/output.js @@ -6,8 +6,11 @@ function () { function Foo() { babelHelpers.classCallCheck(this, Foo); - _foo.set(this, function () { - return this; + _foo.set(this, { + writable: true, + value: function () { + return this; + } }); } diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/canonical/output.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/canonical/output.js index 1075fa4c44..4c9d083cef 100644 --- a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/canonical/output.js +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/canonical/output.js @@ -6,9 +6,15 @@ function () { function Point(_x2 = 0, _y2 = 0) { babelHelpers.classCallCheck(this, Point); - _x.set(this, void 0); + _x.set(this, { + writable: true, + value: void 0 + }); - _y.set(this, void 0); + _y.set(this, { + writable: true, + value: void 0 + }); babelHelpers.classPrivateFieldSet(this, _x, +_x2); babelHelpers.classPrivateFieldSet(this, _y, +_y2); diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/constructor-collision/output.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/constructor-collision/output.js index 2bdbd6dd6b..c77f5b8f74 100644 --- a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/constructor-collision/output.js +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/constructor-collision/output.js @@ -5,7 +5,10 @@ var Foo = function Foo() { babelHelpers.classCallCheck(this, Foo); - _bar.set(this, foo); + _bar.set(this, { + writable: true, + value: foo + }); var _foo = "foo"; }; diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/declaration-order/output.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/declaration-order/output.js index 641d0e5370..06b09aad32 100644 --- a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/declaration-order/output.js +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/declaration-order/output.js @@ -4,7 +4,10 @@ var C = function C() { babelHelpers.classCallCheck(this, C); babelHelpers.defineProperty(this, "y", babelHelpers.classPrivateFieldGet(this, _x)); - _x.set(this, void 0); + _x.set(this, { + writable: true, + value: void 0 + }); }; var _x = new WeakMap(); diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/derived-multiple-supers/output.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/derived-multiple-supers/output.js index 3b8c665873..9b46f9b9e4 100644 --- a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/derived-multiple-supers/output.js +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/derived-multiple-supers/output.js @@ -13,11 +13,17 @@ function (_Bar) { if (condition) { _this = babelHelpers.possibleConstructorReturn(this, babelHelpers.getPrototypeOf(Foo).call(this)); - _bar.set(babelHelpers.assertThisInitialized(babelHelpers.assertThisInitialized(babelHelpers.assertThisInitialized(_this))), "foo"); + _bar.set(babelHelpers.assertThisInitialized(babelHelpers.assertThisInitialized(babelHelpers.assertThisInitialized(_this))), { + writable: true, + value: "foo" + }); } else { _this = babelHelpers.possibleConstructorReturn(this, babelHelpers.getPrototypeOf(Foo).call(this)); - _bar.set(babelHelpers.assertThisInitialized(babelHelpers.assertThisInitialized(babelHelpers.assertThisInitialized(_this))), "foo"); + _bar.set(babelHelpers.assertThisInitialized(babelHelpers.assertThisInitialized(babelHelpers.assertThisInitialized(_this))), { + writable: true, + value: "foo" + }); } return babelHelpers.possibleConstructorReturn(_this); diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/derived/output.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/derived/output.js index 3fa6186f61..c21d6c3186 100644 --- a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/derived/output.js +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/derived/output.js @@ -3,7 +3,10 @@ var Foo = function Foo() { babelHelpers.classCallCheck(this, Foo); - _prop.set(this, "foo"); + _prop.set(this, { + writable: true, + value: "foo" + }); }; var _prop = new WeakMap(); @@ -21,7 +24,10 @@ function (_Foo) { babelHelpers.classCallCheck(this, Bar); _this = babelHelpers.possibleConstructorReturn(this, babelHelpers.getPrototypeOf(Bar).call(this, ...args)); - _prop2.set(babelHelpers.assertThisInitialized(babelHelpers.assertThisInitialized(_this)), "bar"); + _prop2.set(babelHelpers.assertThisInitialized(babelHelpers.assertThisInitialized(_this)), { + writable: true, + value: "bar" + }); return _this; } diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/extracted-this/output.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/extracted-this/output.js index 1da67d41c1..6d741a859b 100644 --- a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/extracted-this/output.js +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/extracted-this/output.js @@ -5,9 +5,15 @@ var Foo = function Foo(_foo) { babelHelpers.classCallCheck(this, Foo); - _bar.set(this, this); + _bar.set(this, { + writable: true, + value: this + }); - _baz.set(this, foo); + _baz.set(this, { + writable: true, + value: foo + }); }; var _bar = new WeakMap(); diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/foobar/output.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/foobar/output.js index efe70074ff..f518512133 100644 --- a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/foobar/output.js +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/foobar/output.js @@ -11,8 +11,11 @@ function (_Parent) { babelHelpers.classCallCheck(this, Child); _this = babelHelpers.possibleConstructorReturn(this, babelHelpers.getPrototypeOf(Child).call(this)); - _scopedFunctionWithThis.set(babelHelpers.assertThisInitialized(babelHelpers.assertThisInitialized(_this)), () => { - _this.name = {}; + _scopedFunctionWithThis.set(babelHelpers.assertThisInitialized(babelHelpers.assertThisInitialized(_this)), { + writable: true, + value: () => { + _this.name = {}; + } }); return _this; diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/instance-undefined/output.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/instance-undefined/output.js index 883eae5647..935e466d2a 100644 --- a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/instance-undefined/output.js +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/instance-undefined/output.js @@ -3,7 +3,10 @@ var Foo = function Foo() { babelHelpers.classCallCheck(this, Foo); - _bar.set(this, void 0); + _bar.set(this, { + writable: true, + value: void 0 + }); }; var _bar = new WeakMap(); diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/instance/output.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/instance/output.js index 33c04bf680..2b1562a16e 100644 --- a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/instance/output.js +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/instance/output.js @@ -3,7 +3,10 @@ var Foo = function Foo() { babelHelpers.classCallCheck(this, Foo); - _bar.set(this, "foo"); + _bar.set(this, { + writable: true, + value: "foo" + }); }; var _bar = new WeakMap(); diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/multiple/output.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/multiple/output.js index 6b96ca95f7..4f2428c717 100644 --- a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/multiple/output.js +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/multiple/output.js @@ -3,9 +3,15 @@ var Foo = function Foo() { babelHelpers.classCallCheck(this, Foo); - _x.set(this, 0); + _x.set(this, { + writable: true, + value: 0 + }); - _y.set(this, babelHelpers.classPrivateFieldGet(this, _x)); + _y.set(this, { + writable: true, + value: babelHelpers.classPrivateFieldGet(this, _x) + }); }; var _x = new WeakMap(); diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/private-in-derived/output.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/private-in-derived/output.js index 8f7b2ea3ad..0ca02451bd 100644 --- a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/private-in-derived/output.js +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/private-in-derived/output.js @@ -3,7 +3,10 @@ var Outer = function Outer() { babelHelpers.classCallCheck(this, Outer); - _outer.set(this, void 0); + _outer.set(this, { + writable: true, + value: void 0 + }); var Test = /*#__PURE__*/ diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/reference-in-other-property/output.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/reference-in-other-property/output.js index 890181b195..74a5672ddd 100644 --- a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/reference-in-other-property/output.js +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/reference-in-other-property/output.js @@ -4,13 +4,22 @@ var Foo = function Foo() { babelHelpers.classCallCheck(this, Foo); babelHelpers.defineProperty(this, "one", babelHelpers.classPrivateFieldGet(this, _private)); - _two.set(this, babelHelpers.classPrivateFieldGet(this, _private)); + _two.set(this, { + writable: true, + value: babelHelpers.classPrivateFieldGet(this, _private) + }); - _private.set(this, 0); + _private.set(this, { + writable: true, + value: 0 + }); babelHelpers.defineProperty(this, "three", babelHelpers.classPrivateFieldGet(this, _private)); - _four.set(this, babelHelpers.classPrivateFieldGet(this, _private)); + _four.set(this, { + writable: true, + value: babelHelpers.classPrivateFieldGet(this, _private) + }); }; var _two = new WeakMap(); diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/regression-T7364/output.mjs b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/regression-T7364/output.mjs index d56a5d7366..7afab86019 100644 --- a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/regression-T7364/output.mjs +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/regression-T7364/output.mjs @@ -4,11 +4,18 @@ class MyClass { constructor() { var _this = this; - _myAsyncMethod.set(this, - /*#__PURE__*/ - babelHelpers.asyncToGenerator(function* () { - console.log(_this); - })); + _myAsyncMethod.set(this, { + writable: true, + value: function () { + var _ref = babelHelpers.asyncToGenerator(function* () { + console.log(_this); + }); + + return function value() { + return _ref.apply(this, arguments); + }; + }() + }); } } @@ -19,11 +26,18 @@ _class = class MyClass2 { constructor() { var _this2 = this; - _myAsyncMethod2.set(this, - /*#__PURE__*/ - babelHelpers.asyncToGenerator(function* () { - console.log(_this2); - })); + _myAsyncMethod2.set(this, { + writable: true, + value: function () { + var _ref2 = babelHelpers.asyncToGenerator(function* () { + console.log(_this2); + }); + + return function value() { + return _ref2.apply(this, arguments); + }; + }() + }); } }; @@ -34,11 +48,18 @@ export default class MyClass3 { constructor() { var _this3 = this; - _myAsyncMethod3.set(this, - /*#__PURE__*/ - babelHelpers.asyncToGenerator(function* () { - console.log(_this3); - })); + _myAsyncMethod3.set(this, { + writable: true, + value: function () { + var _ref3 = babelHelpers.asyncToGenerator(function* () { + console.log(_this3); + }); + + return function value() { + return _ref3.apply(this, arguments); + }; + }() + }); } } diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/super-call/output.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/super-call/output.js index 7afb77a02d..09e9c4b9e1 100644 --- a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/super-call/output.js +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/super-call/output.js @@ -29,7 +29,10 @@ function (_A) { babelHelpers.classCallCheck(this, B); _this = babelHelpers.possibleConstructorReturn(this, babelHelpers.getPrototypeOf(B).call(this, ...args)); - _foo.set(babelHelpers.assertThisInitialized(babelHelpers.assertThisInitialized(_this)), babelHelpers.get(babelHelpers.getPrototypeOf(B.prototype), "foo", babelHelpers.assertThisInitialized(_this)).call(babelHelpers.assertThisInitialized(_this))); + _foo.set(babelHelpers.assertThisInitialized(babelHelpers.assertThisInitialized(_this)), { + writable: true, + value: babelHelpers.get(babelHelpers.getPrototypeOf(B.prototype), "foo", babelHelpers.assertThisInitialized(_this)).call(babelHelpers.assertThisInitialized(_this)) + }); return _this; } diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/super-expression/output.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/super-expression/output.js index 9884d2534a..c887562842 100644 --- a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/super-expression/output.js +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/super-expression/output.js @@ -9,7 +9,10 @@ function (_Bar) { var _temp, _this; babelHelpers.classCallCheck(this, Foo); - foo((_temp = _this = babelHelpers.possibleConstructorReturn(this, babelHelpers.getPrototypeOf(Foo).call(this)), _bar.set(babelHelpers.assertThisInitialized(babelHelpers.assertThisInitialized(_this)), "foo"), _temp)); + foo((_temp = _this = babelHelpers.possibleConstructorReturn(this, babelHelpers.getPrototypeOf(Foo).call(this)), _bar.set(babelHelpers.assertThisInitialized(babelHelpers.assertThisInitialized(_this)), { + writable: true, + value: "foo" + }), _temp)); return _this; } diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/super-statement/output.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/super-statement/output.js index 4221053b3f..ecb55ffde5 100644 --- a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/super-statement/output.js +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/super-statement/output.js @@ -11,7 +11,10 @@ function (_Bar) { babelHelpers.classCallCheck(this, Foo); _this = babelHelpers.possibleConstructorReturn(this, babelHelpers.getPrototypeOf(Foo).call(this)); - _bar.set(babelHelpers.assertThisInitialized(babelHelpers.assertThisInitialized(_this)), "foo"); + _bar.set(babelHelpers.assertThisInitialized(babelHelpers.assertThisInitialized(_this)), { + writable: true, + value: "foo" + }); return _this; } diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/update/output.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/update/output.js index ae86f6bdba..059ef2a091 100644 --- a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/update/output.js +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/update/output.js @@ -6,7 +6,10 @@ function () { function Foo() { babelHelpers.classCallCheck(this, Foo); - _foo.set(this, 0); + _foo.set(this, { + writable: true, + value: 0 + }); } babelHelpers.createClass(Foo, [{