Properly fix-up ClassLiterals in ReparentExpressionScope()

Everything inside a class lives inside the class scope, so
reparenting the class scope is the only operation that
should be done to ClassLiterals during reparenting.

Bug: chromium:740591
Change-Id: Ia5b96b44ff1ca6cfa274effb5a04651809bab9bd
Reviewed-on: https://chromium-review.googlesource.com/588054
Commit-Queue: Adam Klein <adamk@chromium.org>
Reviewed-by: Georg Neis <neis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#46951}
This commit is contained in:
Adam Klein 2017-07-27 10:50:50 -07:00 committed by Commit Bot
parent 100513c0d0
commit 48a903eb3f
2 changed files with 41 additions and 6 deletions

View File

@ -42,21 +42,24 @@ void Rewriter::VisitFunctionLiteral(FunctionLiteral* function_literal) {
void Rewriter::VisitClassLiteral(ClassLiteral* class_literal) {
if (class_literal->extends() != nullptr) {
Visit(class_literal->extends());
}
class_literal->scope()->ReplaceOuterScope(scope_);
// No need to visit the constructor since it will have the class
// scope on its scope chain.
DCHECK_EQ(class_literal->constructor()->scope()->outer_scope(),
class_literal->scope());
#if DEBUG
// The same goes for the rest of the class, but we do some
// sanity checking in debug mode.
ZoneList<ClassLiteralProperty*>* props = class_literal->properties();
for (int i = 0; i < props->length(); ++i) {
ClassLiteralProperty* prop = props->at(i);
if (!prop->key()->IsLiteral()) {
Visit(prop->key());
}
// No need to visit the values, since all values are functions with
// the class scope on their scope chain.
DCHECK(prop->value()->IsFunctionLiteral());
DCHECK_EQ(prop->value()->AsFunctionLiteral()->scope()->outer_scope(),
class_literal->scope());
}
#endif
}

View File

@ -35,3 +35,35 @@
assertEquals(a, b);
}
})();
(function testClassLiteral() {
for (let { a, b = class c { static f() { return a, b } } } of [{}]) {
assertSame(b, (function() { return b.f() })());
}
})();
// Methods in class literals remain inside the
// class scope after scope reparenting.
(function testClassLiteralMethod() {
for (let { a, b = class c { m() { return c } } } of [{}]) {
assertSame(b, (function() { return (new b).m() })());
}
})();
// Function literals in computed class names remain inside the
// class scope after scope reparenting.
(function testClassLiteralComputedName() {
let d;
for (let { a, b = class c { [d = function() { return c }]() { } } } of [{}]) {
assertSame(b, (function() { return b, d() })());
}
})();
// Function literals in class extends expressions names remain inside the
// class scope after scope reparenting.
(function testClassLiteralComputedName() {
let d;
for (let { a, b = class c extends (d = function() { return c }, Object) { } } of [{}]) {
assertSame(b, (function() { return b, d() })());
}
})();