Commit 15a70594 authored by Sathya Gunasekaran's avatar Sathya Gunasekaran Committed by Commit Bot

[class] Parse static private fields

Bug: v8:5368
Change-Id: I0f6edc028baf009b81612ecc4be9a70c3621bc4e
Reviewed-on: https://chromium-review.googlesource.com/c/1385528Reviewed-by: 's avatarAdam Klein <adamk@chromium.org>
Commit-Queue: Sathya Gunasekaran <gsathya@chromium.org>
Cr-Commit-Position: refs/heads/master@{#58416}
parent 66d26a35
...@@ -2006,7 +2006,6 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseProperty( ...@@ -2006,7 +2006,6 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseProperty(
} }
prop_info->name = impl()->GetSymbol(); prop_info->name = impl()->GetSymbol();
if (prop_info->position == PropertyPosition::kObjectLiteral || if (prop_info->position == PropertyPosition::kObjectLiteral ||
prop_info->is_static ||
(!allow_harmony_private_methods() && (!allow_harmony_private_methods() &&
(IsAccessor(prop_info->kind) || (IsAccessor(prop_info->kind) ||
prop_info->kind == ParsePropertyKind::kMethod))) { prop_info->kind == ParsePropertyKind::kMethod))) {
...@@ -2119,10 +2118,6 @@ ParserBase<Impl>::ParseClassPropertyDefinition(ClassInfo* class_info, ...@@ -2119,10 +2118,6 @@ ParserBase<Impl>::ParseClassPropertyDefinition(ClassInfo* class_info,
prop_info->name = impl()->GetSymbol(); prop_info->name = impl()->GetSymbol();
name_expression = name_expression =
factory()->NewStringLiteral(prop_info->name, position()); factory()->NewStringLiteral(prop_info->name, position());
} else if (peek() == Token::PRIVATE_NAME) {
// TODO(gsathya): Make a better error message for this.
ReportUnexpectedToken(Next());
return impl()->NullLiteralProperty();
} else { } else {
prop_info->is_static = true; prop_info->is_static = true;
name_expression = ParseProperty(prop_info); name_expression = ParseProperty(prop_info);
...@@ -2150,22 +2145,27 @@ ParserBase<Impl>::ParseClassPropertyDefinition(ClassInfo* class_info, ...@@ -2150,22 +2145,27 @@ ParserBase<Impl>::ParseClassPropertyDefinition(ClassInfo* class_info,
// name as an uninitialized field. // name as an uninitialized field.
if (allow_harmony_public_fields() || allow_harmony_private_fields()) { if (allow_harmony_public_fields() || allow_harmony_private_fields()) {
prop_info->kind = ParsePropertyKind::kClassField; prop_info->kind = ParsePropertyKind::kClassField;
prop_info->is_private = name_token == Token::PRIVATE_NAME; DCHECK_IMPLIES(prop_info->is_computed_name, !prop_info->is_private);
if (prop_info->is_static && !allow_harmony_static_fields()) { if (prop_info->is_static && !allow_harmony_static_fields()) {
ReportUnexpectedToken(Next()); ReportUnexpectedToken(Next());
return impl()->NullLiteralProperty(); return impl()->NullLiteralProperty();
} }
if (!prop_info->is_computed_name) { if (!prop_info->is_computed_name) {
CheckClassFieldName(prop_info->name, prop_info->is_static); CheckClassFieldName(prop_info->name, prop_info->is_static);
} }
ExpressionT initializer = ParseMemberInitializer( ExpressionT initializer = ParseMemberInitializer(
class_info, property_beg_pos, prop_info->is_static); class_info, property_beg_pos, prop_info->is_static);
ExpectSemicolon(); ExpectSemicolon();
ClassLiteralPropertyT result = factory()->NewClassLiteralProperty( ClassLiteralPropertyT result = factory()->NewClassLiteralProperty(
name_expression, initializer, ClassLiteralProperty::FIELD, name_expression, initializer, ClassLiteralProperty::FIELD,
prop_info->is_static, prop_info->is_computed_name, prop_info->is_static, prop_info->is_computed_name,
prop_info->is_private); prop_info->is_private);
impl()->SetFunctionNameFromPropertyName(result, prop_info->name); impl()->SetFunctionNameFromPropertyName(result, prop_info->name);
return result; return result;
} else { } else {
...@@ -4210,8 +4210,9 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseClassLiteral( ...@@ -4210,8 +4210,9 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseClassLiteral(
prop_info.is_computed_name) { prop_info.is_computed_name) {
class_info.has_static_computed_names = true; class_info.has_static_computed_names = true;
} }
if (prop_info.is_computed_name && !prop_info.is_private && if (prop_info.is_computed_name &&
property_kind == ClassLiteralProperty::FIELD) { property_kind == ClassLiteralProperty::FIELD) {
DCHECK(!prop_info.is_private);
class_info.computed_field_count++; class_info.computed_field_count++;
} }
is_constructor &= class_info.has_seen_constructor; is_constructor &= class_info.has_seen_constructor;
......
...@@ -3071,7 +3071,6 @@ void Parser::DeclareClassProperty(const AstRawString* class_name, ...@@ -3071,7 +3071,6 @@ void Parser::DeclareClassProperty(const AstRawString* class_name,
if (is_static) { if (is_static) {
DCHECK(allow_harmony_static_fields()); DCHECK(allow_harmony_static_fields());
DCHECK_EQ(kind, ClassLiteralProperty::FIELD); DCHECK_EQ(kind, ClassLiteralProperty::FIELD);
DCHECK(!is_private);
class_info->static_fields->Add(property, zone()); class_info->static_fields->Add(property, zone());
} else { } else {
class_info->instance_fields->Add(property, zone()); class_info->instance_fields->Add(property, zone());
......
...@@ -5698,7 +5698,7 @@ TEST(PrivateClassFieldsErrors) { ...@@ -5698,7 +5698,7 @@ TEST(PrivateClassFieldsErrors) {
private_fields, arraysize(private_fields)); private_fields, arraysize(private_fields));
} }
TEST(PrivateStaticClassFieldsErrors) { TEST(PrivateStaticClassFieldsNoErrors) {
// clang-format off // clang-format off
// Tests proposed class fields syntax. // Tests proposed class fields syntax.
const char* context_data[][2] = {{"(class {", "});"}, const char* context_data[][2] = {{"(class {", "});"},
...@@ -5719,6 +5719,71 @@ TEST(PrivateStaticClassFieldsErrors) { ...@@ -5719,6 +5719,71 @@ TEST(PrivateStaticClassFieldsErrors) {
"static #a; b(){}", "static #a; b(){}",
"static #a; *b(){}", "static #a; *b(){}",
"static #a; ['b'](){}", "static #a; ['b'](){}",
"#prototype",
"#prototype = function() {}",
// ASI
"static #a = 0\n",
"static #a = 0\n b",
"static #a = 0\n #b",
"static #a = 0\n b(){}",
"static #a\n",
"static #a\n b\n",
"static #a\n #b\n",
"static #a\n b(){}",
"static #a\n *b(){}",
"static #a\n ['b'](){}",
"static #a = function t() { arguments; }",
"static #a = () => function t() { arguments; }",
// ASI edge cases
"static #a\n get",
"static #get\n *a(){}",
"static #a\n static",
// Misc edge cases
"static #yield",
"static #yield = 0",
"static #yield\n a",
"static #async;",
"static #async = 0;",
"static #async",
"static #async = 0",
"static #async\n a(){}", // a field named async, and a method named a.
"static #async\n a",
"static #await;",
"static #await = 0;",
"static #await\n a",
nullptr
};
// clang-format on
RunParserSyncTest(context_data, class_body_data, kError);
static const ParserFlag public_static_fields[] = {kAllowHarmonyPublicFields,
kAllowHarmonyStaticFields};
RunParserSyncTest(context_data, class_body_data, kError, nullptr, 0,
public_static_fields, arraysize(public_static_fields));
static const ParserFlag private_static_fields[] = {
kAllowHarmonyPublicFields, kAllowHarmonyStaticFields,
kAllowHarmonyPrivateFields};
RunParserSyncTest(context_data, class_body_data, kSuccess, nullptr, 0,
private_static_fields, arraysize(private_static_fields));
}
TEST(PrivateStaticClassFieldsErrors) {
// clang-format off
// Tests proposed class fields syntax.
const char* context_data[][2] = {{"(class {", "});"},
{"(class extends Base {", "});"},
{"class C {", "}"},
{"class C extends Base {", "}"},
{nullptr, nullptr}};
const char* class_body_data[] = {
// Basic syntax
"static #['a'] = 0;", "static #['a'] = 0;",
"static #['a'] = 0; b", "static #['a'] = 0; b",
"static #['a'] = 0; #b", "static #['a'] = 0; #b",
...@@ -5743,6 +5808,14 @@ TEST(PrivateStaticClassFieldsErrors) { ...@@ -5743,6 +5808,14 @@ TEST(PrivateStaticClassFieldsErrors) {
"static #*a() { }", "static #*a() { }",
"static async #*a() { }", "static async #*a() { }",
"#a = arguments",
"#a = () => arguments",
"#a = () => { arguments }",
"#a = arguments[0]",
"#a = delete arguments[0]",
"#a = f(arguments)",
"#a = () => () => arguments",
// TODO(joyee): support static private methods // TODO(joyee): support static private methods
"static #a() { }", "static #a() { }",
"static get #a() { }", "static get #a() { }",
...@@ -5752,16 +5825,6 @@ TEST(PrivateStaticClassFieldsErrors) { ...@@ -5752,16 +5825,6 @@ TEST(PrivateStaticClassFieldsErrors) {
"static async *#a() { }", "static async *#a() { }",
// ASI // ASI
"static #a = 0\n",
"static #a = 0\n b",
"static #a = 0\n #b",
"static #a = 0\n b(){}",
"static #a\n",
"static #a\n b\n",
"static #a\n #b\n",
"static #a\n b(){}",
"static #a\n *b(){}",
"static #a\n ['b'](){}",
"static #['a'] = 0\n", "static #['a'] = 0\n",
"static #['a'] = 0\n b", "static #['a'] = 0\n b",
"static #['a'] = 0\n #b", "static #['a'] = 0\n #b",
...@@ -5773,27 +5836,34 @@ TEST(PrivateStaticClassFieldsErrors) { ...@@ -5773,27 +5836,34 @@ TEST(PrivateStaticClassFieldsErrors) {
"static #['a']\n *b(){}", "static #['a']\n *b(){}",
"static #['a']\n ['b'](){}", "static #['a']\n ['b'](){}",
"static #a = function t() { arguments; }", // ASI requires a linebreak
"static #a = () => function t() { arguments; }", "static #a b",
"static #a = 0 b",
// ASI edge cases // ASI requires that the next token is not part of any legal production
"static #a\n get", "static #a = 0\n *b(){}",
"static #get\n *a(){}", "static #a = 0\n ['b'](){}",
"static #a\n static",
"static #a : 0",
"static #a =",
"static #*a = 0",
"static #*a",
"static #get a",
"static #yield a",
"static #async a = 0",
"static #async a",
"static # a = 0",
// Misc edge cases "#constructor",
"static #yield", "#constructor = function() {}",
"static #yield = 0",
"static #yield\n a", "foo() { delete this.#a }",
"static #async;", "foo() { delete this.x.#a }",
"static #async = 0;", "foo() { delete this.x().#a }",
"static #async",
"static #async = 0", "foo() { delete f.#a }",
"static #async\n a(){}", // a field named async, and a method named a. "foo() { delete f.x.#a }",
"static #async\n a", "foo() { delete f.x().#a }",
"static #await;",
"static #await = 0;",
"static #await\n a",
nullptr nullptr
}; };
// clang-format on // clang-format on
......
...@@ -44,6 +44,8 @@ from testrunner.outproc import test262 ...@@ -44,6 +44,8 @@ from testrunner.outproc import test262
FEATURE_FLAGS = { FEATURE_FLAGS = {
'class-fields-public': '--harmony-public-fields', 'class-fields-public': '--harmony-public-fields',
'class-static-fields-public': '--harmony-class-fields', 'class-static-fields-public': '--harmony-class-fields',
'class-fields-private': '--harmony-private-fields',
'class-static-fields-private': '--harmony-private-fields',
'Array.prototype.flat': '--harmony-array-flat', 'Array.prototype.flat': '--harmony-array-flat',
'Array.prototype.flatMap': '--harmony-array-flat', 'Array.prototype.flatMap': '--harmony-array-flat',
'String.prototype.matchAll': '--harmony-string-matchall', 'String.prototype.matchAll': '--harmony-string-matchall',
...@@ -60,9 +62,7 @@ FEATURE_FLAGS = { ...@@ -60,9 +62,7 @@ FEATURE_FLAGS = {
'Object.fromEntries': '--harmony-object-from-entries', 'Object.fromEntries': '--harmony-object-from-entries',
} }
SKIPPED_FEATURES = set(['class-fields-private', SKIPPED_FEATURES = set(['class-methods-private',
'class-static-fields-private',
'class-methods-private',
'class-static-methods-private', 'class-static-methods-private',
'Intl.NumberFormat-unified']) 'Intl.NumberFormat-unified'])
......
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