Skip to content

Commit

Permalink
Fix evaluation order of decorators with cached receiver (#16281)
Browse files Browse the repository at this point in the history
* Add failing test

* Fix evaluation order of decorators with cached receiver

* Use one temp var per decorated element

* Use one temp var per class
  • Loading branch information
nicolo-ribaudo committed Feb 27, 2024
1 parent 7e1096f commit b723491
Show file tree
Hide file tree
Showing 18 changed files with 111 additions and 91 deletions.
Expand Up @@ -909,6 +909,7 @@ function transformClass(
const decoratedPrivateMethods = new Set<string>();

let classInitLocal: t.Identifier, classIdLocal: t.Identifier;
let decoratorReceiverId: t.Identifier | null = null;

// Memoise the this value `a.b` of decorator member expressions `@a.b.dec`,
type HandleDecoratorExpressionsResult = {
Expand All @@ -929,16 +930,19 @@ function transformClass(
(!process.env.BABEL_8_BREAKING && version === "2023-05")) &&
t.isMemberExpression(expression)
) {
if (
t.isSuper(expression.object) ||
t.isThisExpression(expression.object)
) {
object = memoiseExpression(t.thisExpression(), "obj");
} else {
if (!scopeParent.isStatic(expression.object)) {
expression.object = memoiseExpression(expression.object, "obj");
}
if (t.isSuper(expression.object)) {
object = t.thisExpression();
} else if (scopeParent.isStatic(expression.object)) {
object = t.cloneNode(expression.object);
} else {
decoratorReceiverId ??=
scopeParent.generateDeclaredUidIdentifier("obj");
object = t.assignmentExpression(
"=",
t.cloneNode(decoratorReceiverId),
expression.object,
);
expression.object = t.cloneNode(decoratorReceiverId);
}
}
decoratorsThis.push(object);
Expand Down
@@ -1,10 +1,8 @@
class A extends B {
m() {
var _initProto, _initClass, _obj, _classDecs, _obj2, _m2Decs, _C2;
_obj = this;
_classDecs = [_obj, super.dec1];
_obj2 = this;
_m2Decs = [_obj2, super.dec2];
var _initProto, _initClass, _classDecs, _m2Decs, _C2;
_classDecs = [this, super.dec1];
_m2Decs = [this, super.dec2];
let _C;
class C {
constructor() {
Expand Down
@@ -1,12 +1,7 @@
var _initClass, _obj, _obj2, _classDecs, _obj3, _obj4, _xDecs, _init_x, _obj5, _yDecs, _init_y, _A2;
_obj = o1;
_obj2 = o2;
_classDecs = [_obj, _obj.dec, void 0, dec, _obj2, _obj2.dec];
_obj3 = o2;
_obj4 = o3.o;
_xDecs = [_obj3, _obj3.dec, _obj4, _obj4.dec];
_obj5 = o2;
_yDecs = [_obj5, _obj5.dec, void 0, dec];
var _initClass, _obj, _classDecs, _xDecs, _init_x, _yDecs, _init_y, _A2;
_classDecs = [_obj = o1, _obj.dec, void 0, dec, _obj = o2, _obj.dec];
_xDecs = [_obj = o2, _obj.dec, _obj = o3.o, _obj.dec];
_yDecs = [_obj = o2, _obj.dec, void 0, dec];
let _A;
class A {
constructor() {
Expand Down
@@ -1,9 +1,7 @@
var _initProto, _initClass, _obj, _classDecs, _obj2, _methodDecs, _Foo2;
var _initProto, _initClass, _obj, _classDecs, _methodDecs, _Foo2;
const dec = () => {};
_obj = array;
_classDecs = [void 0, dec, void 0, call(), void 0, chain.expr(), void 0, arbitrary + expr, _obj, _obj[expr]];
_obj2 = array;
_methodDecs = [void 0, dec, void 0, call(), void 0, chain.expr(), void 0, arbitrary + expr, _obj2, _obj2[expr]];
_classDecs = [void 0, dec, void 0, call(), void 0, chain.expr(), void 0, arbitrary + expr, _obj = array, _obj[expr]];
_methodDecs = [void 0, dec, void 0, call(), void 0, chain.expr(), void 0, arbitrary + expr, _obj = array, _obj[expr]];
let _Foo;
var _a = /*#__PURE__*/new WeakMap();
class Foo {
Expand Down
@@ -1,10 +1,8 @@
class A extends B {
m() {
var _initProto, _initClass, _obj, _classDecs, _obj2, _m2Decs;
_obj = this;
_classDecs = [_obj, super.dec1];
_obj2 = this;
_m2Decs = [_obj2, super.dec2];
var _initProto, _initClass, _classDecs, _m2Decs;
_classDecs = [this, super.dec1];
_m2Decs = [this, super.dec2];
let _C;
class C {
static {
Expand Down
@@ -1,12 +1,7 @@
var _initClass, _obj, _obj2, _classDecs, _obj3, _obj4, _xDecs, _init_x, _obj5, _yDecs, _init_y;
_obj = o1;
_obj2 = o2;
_classDecs = [_obj, _obj.dec, void 0, dec, _obj2, _obj2.dec];
_obj3 = o2;
_obj4 = o3.o;
_xDecs = [_obj3, _obj3.dec, _obj4, _obj4.dec];
_obj5 = o2;
_yDecs = [_obj5, _obj5.dec, void 0, dec];
var _initClass, _obj, _classDecs, _xDecs, _init_x, _yDecs, _init_y;
_classDecs = [_obj = o1, _obj.dec, void 0, dec, _obj = o2, _obj.dec];
_xDecs = [_obj = o2, _obj.dec, _obj = o3.o, _obj.dec];
_yDecs = [_obj = o2, _obj.dec, void 0, dec];
let _A;
class A {
static {
Expand Down
@@ -1,9 +1,7 @@
var _initProto, _initClass, _obj, _classDecs, _obj2, _methodDecs;
var _initProto, _initClass, _obj, _classDecs, _methodDecs;
const dec = () => {};
_obj = array;
_classDecs = [void 0, dec, void 0, call(), void 0, chain.expr(), void 0, arbitrary + expr, _obj, _obj[expr]];
_obj2 = array;
_methodDecs = [void 0, dec, void 0, call(), void 0, chain.expr(), void 0, arbitrary + expr, _obj2, _obj2[expr]];
_classDecs = [void 0, dec, void 0, call(), void 0, chain.expr(), void 0, arbitrary + expr, _obj = array, _obj[expr]];
_methodDecs = [void 0, dec, void 0, call(), void 0, chain.expr(), void 0, arbitrary + expr, _obj = array, _obj[expr]];
let _Foo;
class Foo {
static {
Expand All @@ -15,8 +13,8 @@ class Foo {
#a = void _initProto(this);
method() {}
makeClass() {
var _obj3, _barDecs, _init_bar;
return _obj3 = this, _barDecs = [_obj3, this.#a], class Nested {
var _barDecs, _init_bar;
return _barDecs = [this, this.#a], class Nested {
static {
[_init_bar] = babelHelpers.applyDecs2305(this, [[_barDecs, 16, "bar"]], []).e;
}
Expand Down
@@ -1,10 +1,8 @@
class A extends B {
m() {
var _initProto, _initClass, _obj, _classDecs, _obj2, _m2Decs, _C2;
_obj = this;
_classDecs = [_obj, super.dec1];
_obj2 = this;
_m2Decs = [_obj2, super.dec2];
var _initProto, _initClass, _classDecs, _m2Decs, _C2;
_classDecs = [this, super.dec1];
_m2Decs = [this, super.dec2];
let _C;
class C {
constructor() {
Expand Down
@@ -1,12 +1,7 @@
var _initClass, _obj, _obj2, _classDecs, _obj3, _obj4, _xDecs, _init_x, _init_extra_x, _obj5, _yDecs, _init_y, _init_extra_y, _A2;
_obj = o1;
_obj2 = o2;
_classDecs = [_obj, _obj.dec, void 0, dec, _obj2, _obj2.dec];
_obj3 = o2;
_obj4 = o3.o;
_xDecs = [_obj3, _obj3.dec, _obj4, _obj4.dec];
_obj5 = o2;
_yDecs = [_obj5, _obj5.dec, void 0, dec];
var _initClass, _obj, _classDecs, _xDecs, _init_x, _init_extra_x, _yDecs, _init_y, _init_extra_y, _A2;
_classDecs = [_obj = o1, _obj.dec, void 0, dec, _obj = o2, _obj.dec];
_xDecs = [_obj = o2, _obj.dec, _obj = o3.o, _obj.dec];
_yDecs = [_obj = o2, _obj.dec, void 0, dec];
let _A;
class A {
constructor() {
Expand Down
@@ -1,9 +1,7 @@
var _initProto, _initClass, _obj, _classDecs, _obj2, _methodDecs, _Foo2;
var _initProto, _initClass, _obj, _classDecs, _methodDecs, _Foo2;
const dec = () => {};
_obj = array;
_classDecs = [void 0, dec, void 0, call(), void 0, chain.expr(), void 0, arbitrary + expr, _obj, _obj[expr]];
_obj2 = array;
_methodDecs = [void 0, dec, void 0, call(), void 0, chain.expr(), void 0, arbitrary + expr, _obj2, _obj2[expr]];
_classDecs = [void 0, dec, void 0, call(), void 0, chain.expr(), void 0, arbitrary + expr, _obj = array, _obj[expr]];
_methodDecs = [void 0, dec, void 0, call(), void 0, chain.expr(), void 0, arbitrary + expr, _obj = array, _obj[expr]];
let _Foo;
var _a = /*#__PURE__*/new WeakMap();
class Foo {
Expand Down
@@ -1,10 +1,8 @@
class A extends B {
m() {
var _initProto, _initClass, _obj, _classDecs, _obj2, _m2Decs;
_obj = this;
_classDecs = [_obj, super.dec1];
_obj2 = this;
_m2Decs = [_obj2, super.dec2];
var _initProto, _initClass, _classDecs, _m2Decs;
_classDecs = [this, super.dec1];
_m2Decs = [this, super.dec2];
let _C;
class C {
static {
Expand Down
@@ -1,14 +1,7 @@
var _initClass, _obj, _obj2, _obj3, _classDecs, _obj4, _obj5, _obj6, _xDecs, _init_x, _init_extra_x, _obj7, _yDecs, _init_y, _init_extra_y;
_obj = o1;
_obj2 = o2;
_obj3 = o4.o();
_classDecs = [_obj, _obj.dec, void 0, dec, _obj2, _obj2.dec, _obj3, _obj3.dec];
_obj4 = o2;
_obj5 = o3.o;
_obj6 = o4.o();
_xDecs = [_obj4, _obj4.dec, _obj5, _obj5.dec, _obj6, _obj6.dec];
_obj7 = o2;
_yDecs = [_obj7, _obj7.dec, void 0, dec];
var _initClass, _obj, _classDecs, _xDecs, _init_x, _init_extra_x, _yDecs, _init_y, _init_extra_y;
_classDecs = [_obj = o1, _obj.dec, void 0, dec, _obj = o2, _obj.dec, _obj = o4.o(), _obj.dec];
_xDecs = [_obj = o2, _obj.dec, _obj = o3.o, _obj.dec, _obj = o4.o(), _obj.dec];
_yDecs = [_obj = o2, _obj.dec, void 0, dec];
let _A;
class A {
static {
Expand Down
@@ -1,9 +1,7 @@
var _initProto, _initClass, _obj, _classDecs, _obj2, _methodDecs;
var _initProto, _initClass, _obj, _classDecs, _methodDecs;
const dec = () => {};
_obj = array;
_classDecs = [void 0, dec, void 0, call(), void 0, chain.expr(), void 0, arbitrary + expr, _obj, _obj[expr]];
_obj2 = array;
_methodDecs = [void 0, dec, void 0, call(), void 0, chain.expr(), void 0, arbitrary + expr, _obj2, _obj2[expr]];
_classDecs = [void 0, dec, void 0, call(), void 0, chain.expr(), void 0, arbitrary + expr, _obj = array, _obj[expr]];
_methodDecs = [void 0, dec, void 0, call(), void 0, chain.expr(), void 0, arbitrary + expr, _obj = array, _obj[expr]];
let _Foo;
class Foo {
static {
Expand All @@ -15,8 +13,8 @@ class Foo {
#a = void _initProto(this);
method() {}
makeClass() {
var _obj3, _barDecs, _init_bar, _init_extra_bar;
return _obj3 = this, _barDecs = [_obj3, this.#a], class Nested {
var _barDecs, _init_bar, _init_extra_bar;
return _barDecs = [this, this.#a], class Nested {
static {
[_init_bar, _init_extra_bar] = babelHelpers.applyDecs2311(this, [[_barDecs, 16, "bar"]], []).e;
}
Expand Down
@@ -0,0 +1,17 @@
let result = [];
const fn = () => { result.push(1); return () => {} }
const obj = {
get prop() {
result.push(2);
return {
get foo() { result.push(3); return () => {} }
}
}
};
class A {
@fn()
@obj.prop.foo
method() {}
}

expect(result).toEqual([1, 2, 3]);
@@ -0,0 +1,7 @@
let fn, obj;
class A {
@fn()
@obj.prop.foo
method() {}
}

@@ -0,0 +1,11 @@
var _initProto, _obj, _methodDecs, _A;
let fn, obj;
_methodDecs = [void 0, fn(), _obj = obj.prop, _obj.foo];
class A {
constructor() {
_initProto(this);
}
method() {}
}
_A = A;
[_initProto] = babelHelpers.applyDecs2311(_A, [[_methodDecs, 18, "method"]], []).e;
@@ -0,0 +1,7 @@
let fn, obj;
class A {
@fn()
@obj.prop.foo
method() {}
}

@@ -0,0 +1,12 @@
var _initProto, _obj, _methodDecs;
let fn, obj;
_methodDecs = [void 0, fn(), _obj = obj.prop, _obj.foo];
class A {
static {
[_initProto] = babelHelpers.applyDecs2311(this, [[_methodDecs, 18, "method"]], []).e;
}
constructor() {
_initProto(this);
}
method() {}
}

0 comments on commit b723491

Please sign in to comment.