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, 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( function replaceThisContext(
path, path,
ref, ref,
@ -676,8 +687,13 @@ function replaceThisContext(
file, file,
isStaticBlock, isStaticBlock,
constantSuper, constantSuper,
innerBindingRef,
) { ) {
const state = { classRef: ref, needsClassRef: false }; const state = {
classRef: ref,
needsClassRef: false,
innerBinding: innerBindingRef,
};
const replacer = new ReplaceSupers({ const replacer = new ReplaceSupers({
methodPath: path, methodPath: path,
@ -696,6 +712,11 @@ function replaceThisContext(
if (isStaticBlock || path.isProperty()) { if (isStaticBlock || path.isProperty()) {
path.traverse(thisContextVisitor, state); path.traverse(thisContextVisitor, state);
} }
if (state.classRef?.name && state.classRef.name !== innerBindingRef?.name) {
path.traverse(innerReferencesVisitor, state);
}
return state.needsClassRef; return state.needsClassRef;
} }
@ -708,6 +729,7 @@ export function buildFieldsInitNodes(
setPublicClassFields, setPublicClassFields,
privateFieldsAsProperties, privateFieldsAsProperties,
constantSuper, constantSuper,
innerBindingRef,
) { ) {
let needsClassRef = false; let needsClassRef = false;
let injectSuperRef; let injectSuperRef;
@ -743,6 +765,7 @@ export function buildFieldsInitNodes(
state, state,
isStaticBlock, isStaticBlock,
constantSuper, constantSuper,
innerBindingRef,
); );
needsClassRef = needsClassRef || replaced; needsClassRef = needsClassRef || replaced;
} }

View File

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