fix: reference to class expression in private method (#13429)

Co-authored-by: Henry Zhu <hi@henryzoo.com>
Co-authored-by: Federico Ciardi <fed.ciardi@gmail.com>
Co-authored-by: Nicolò Ribaudo <nicolo.ribaudo@gmail.com>
This commit is contained in:
Lively 2021-06-15 00:06:22 +09:00 committed by GitHub
parent 69f423b873
commit 903b600522
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 128 additions and 3 deletions

View File

@ -669,6 +669,17 @@ const thisContextVisitor = traverse.visitors.merge([
environmentVisitor,
]);
const innerReferencesVisitor = {
ReferencedIdentifier(path, state) {
if (
path.scope.bindingIdentifierEquals(path.node.name, state.innerBinding)
) {
state.needsClassRef = true;
path.node.name = state.classRef.name;
}
},
};
function replaceThisContext(
path,
ref,
@ -676,8 +687,13 @@ function replaceThisContext(
file,
isStaticBlock,
constantSuper,
innerBindingRef,
) {
const state = { classRef: ref, needsClassRef: false };
const state = {
classRef: ref,
needsClassRef: false,
innerBinding: innerBindingRef,
};
const replacer = new ReplaceSupers({
methodPath: path,
@ -696,6 +712,11 @@ function replaceThisContext(
if (isStaticBlock || path.isProperty()) {
path.traverse(thisContextVisitor, state);
}
if (state.classRef?.name && state.classRef.name !== innerBindingRef?.name) {
path.traverse(innerReferencesVisitor, state);
}
return state.needsClassRef;
}
@ -708,6 +729,7 @@ export function buildFieldsInitNodes(
setPublicClassFields,
privateFieldsAsProperties,
constantSuper,
innerBindingRef,
) {
let needsClassRef = false;
let injectSuperRef;
@ -743,6 +765,7 @@ export function buildFieldsInitNodes(
state,
isStaticBlock,
constantSuper,
innerBindingRef,
);
needsClassRef = needsClassRef || replaced;
}

View File

@ -168,9 +168,9 @@ export function createClassFeaturePlugin({
if (!props.length && !isDecorated) return;
const innerBinding = path.node.id;
let ref;
if (path.isClassExpression() || !path.node.id) {
if (!innerBinding || path.isClassExpression()) {
nameFunction(path);
ref = path.scope.generateUidIdentifier("class");
} else {
@ -220,6 +220,7 @@ export function createClassFeaturePlugin({
setPublicClassFields ?? loose,
privateFieldsAsProperties ?? loose,
constantSuper ?? loose,
innerBinding,
));
}

View File

@ -0,0 +1,15 @@
const f = class Foo {
static #x = Foo;
static y = Foo;
static extract() {
return {
x: Foo.#x,
y: Foo.y,
}
}
};
const { x, y } = f.extract();
expect(x).toBe(f)
expect(y).toBe(f)

View File

@ -0,0 +1,4 @@
const f = class Foo {
static #x = Foo;
static y = Foo;
}

View File

@ -0,0 +1,3 @@
{
"plugins": ["proposal-class-properties", "transform-block-scoping"]
}

View File

@ -0,0 +1,6 @@
var _class, _temp, _x;
var f = (_temp = _class = class Foo {}, _x = {
writable: true,
value: _class
}, babelHelpers.defineProperty(_class, "y", _class), _temp);

View File

@ -0,0 +1,31 @@
const f = class Foo {
static #bar() {
return Foo;
}
static #method() {
return function inner() {
return Foo;
};
}
static #method_shadowed() {
new Foo();
return function inner() {
let Foo = 3;
return Foo;
}
}
static extract() {
return {
bar: Foo.#bar,
method: Foo.#method,
method_shadowed: Foo.#method_shadowed
}
}
};
const { bar, method, method_shadowed } = f.extract();
expect(bar()).toBe(f)
expect(method()()).toBe(f)
expect(method_shadowed()()).toBe(3)

View File

@ -0,0 +1,18 @@
const f = class Foo {
static #bar() {
return Foo;
}
static #method() {
return function inner() {
return Foo;
};
}
static #method_shadowed() {
new Foo();
return function inner() {
let Foo = 3;
return Foo;
}
}
}

View File

@ -0,0 +1,3 @@
{
"plugins": ["proposal-class-properties", "transform-block-scoping"]
}

View File

@ -0,0 +1,21 @@
var _class;
var f = _class = class Foo {};
function _bar() {
return _class;
}
function _method() {
return function inner() {
return _class;
};
}
function _method_shadowed() {
new _class();
return function inner() {
var Foo = 3;
return Foo;
};
}