Commit 5c59fe02 authored by Sathya Gunasekaran's avatar Sathya Gunasekaran Committed by Commit Bot

[class] Fix preparsed scope data mismatch for computed class fields

Previously we only created synthetic variables in the parser and not
in the preparser, causing mismatch in the preparsed scope data.

This patch creates the variables in both parsers.

Bug: v8:5367
Change-Id: I9c511d0b9212bd36816956b06dc204b0b5920e1c
Reviewed-on: https://chromium-review.googlesource.com/789848
Commit-Queue: Sathya Gunasekaran <gsathya@chromium.org>
Reviewed-by: 's avatarGeorg Neis <neis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#49637}
parent abbd856e
......@@ -566,7 +566,8 @@ class ParserBase {
has_instance_class_fields(false),
is_anonymous(false),
static_fields_scope(nullptr),
instance_fields_scope(nullptr) {}
instance_fields_scope(nullptr),
computed_field_count(0) {}
Variable* variable;
ExpressionT extends;
typename Types::ClassPropertyList properties;
......@@ -583,8 +584,15 @@ class ParserBase {
bool is_anonymous;
DeclarationScope* static_fields_scope;
DeclarationScope* instance_fields_scope;
int computed_field_count;
};
const AstRawString* ClassFieldVariableName(AstValueFactory* ast_value_factory,
int index) {
std::string name = ".class-field-" + std::to_string(index);
return ast_value_factory->GetOneByteString(name.c_str());
}
DeclarationScope* NewScriptScope() const {
return new (zone()) DeclarationScope(zone(), ast_value_factory());
}
......@@ -4507,12 +4515,16 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseClassLiteral(
is_computed_name) {
class_info.has_static_computed_names = true;
}
if (is_computed_name && property_kind == ClassLiteralProperty::FIELD) {
class_info.computed_field_count++;
}
is_constructor &= class_info.has_seen_constructor;
impl()->RewriteNonPattern(CHECK_OK);
AccumulateFormalParameterContainmentErrors();
impl()->DeclareClassProperty(name, property, property_kind, is_static,
is_constructor, &class_info, CHECK_OK);
is_constructor, is_computed_name, &class_info,
CHECK_OK);
impl()->InferFunctionName();
}
......
......@@ -3215,16 +3215,6 @@ void Parser::DeclareClassVariable(const AstRawString* name,
}
}
namespace {
const AstRawString* ClassFieldVariableName(AstValueFactory* ast_value_factory,
int index) {
std::string name = ".class-field-" + std::to_string(index);
return ast_value_factory->GetOneByteString(name.c_str());
}
} // namespace
// TODO(gsathya): Ideally, this should just bypass scope analysis and
// allocate a slot directly on the context. We should just store this
// index in the AST, instead of storing the variable.
......@@ -3247,7 +3237,8 @@ void Parser::DeclareClassProperty(const AstRawString* class_name,
ClassLiteralProperty* property,
ClassLiteralProperty::Kind kind,
bool is_static, bool is_constructor,
ClassInfo* class_info, bool* ok) {
bool is_computed_name, ClassInfo* class_info,
bool* ok) {
if (is_constructor) {
DCHECK(!class_info->constructor);
class_info->constructor = property->value()->AsFunctionLiteral();
......@@ -3258,7 +3249,7 @@ void Parser::DeclareClassProperty(const AstRawString* class_name,
return;
}
if (property->kind() != ClassLiteralProperty::FIELD) {
if (kind != ClassLiteralProperty::FIELD) {
class_info->properties->Add(property, zone());
return;
}
......@@ -3271,14 +3262,13 @@ void Parser::DeclareClassProperty(const AstRawString* class_name,
class_info->instance_fields->Add(property, zone());
}
int index = class_info->static_fields->length() +
class_info->instance_fields->length();
if (property->is_computed_name()) {
if (is_computed_name) {
// We create a synthetic variable name here so that scope
// analysis doesn't dedupe the vars.
Variable* computed_name_var = CreateSyntheticContextVariable(
ClassFieldVariableName(ast_value_factory(), index), CHECK_OK_VOID);
ClassFieldVariableName(ast_value_factory(),
class_info->computed_field_count),
CHECK_OK_VOID);
property->set_computed_name_var(computed_name_var);
class_info->properties->Add(property, zone());
}
......
......@@ -370,6 +370,7 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
ClassLiteralProperty* property,
ClassLiteralProperty::Kind kind,
bool is_static, bool is_constructor,
bool is_computed_name,
ClassInfo* class_info, bool* ok);
V8_INLINE Expression* RewriteClassLiteral(Scope* block_scope,
const AstRawString* name,
......
......@@ -1153,7 +1153,16 @@ class PreParser : public ParserBase<PreParser> {
const PreParserExpression& property,
ClassLiteralProperty::Kind kind,
bool is_static, bool is_constructor,
ClassInfo* class_info, bool* ok) {}
bool is_computed_name,
ClassInfo* class_info, bool* ok) {
if (kind == ClassLiteralProperty::FIELD && is_computed_name) {
scope()->DeclareVariableName(
ClassFieldVariableName(ast_value_factory(),
class_info->computed_field_count),
CONST);
}
}
V8_INLINE PreParserExpression
RewriteClassLiteral(Scope* scope, const PreParserIdentifier& name,
ClassInfo* class_info, int pos, int end_pos, bool* ok) {
......
......@@ -599,3 +599,29 @@ x();
let x = new X;
assertEquals(1, x.c);
}
{
function t() {
return class {
['x'] = 1;
}
}
let klass = t();
let obj = new klass;
assertEquals(1, obj.x);
}
{
function t() {
return class {
['x'] = 1;
static ['x'] = 2;
}
}
let klass = t();
let obj = new klass;
assertEquals(1, obj.x);
assertEquals(2, klass.x);
}
......@@ -321,3 +321,15 @@ x();
assertThrows(() => { class X { static [X] } });
assertEquals(undefined, D[C]);
}
{
function t() {
return class {
static ['x'] = 2;
}
}
let klass = t();
let obj = new klass;
assertEquals(2, klass.x);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment