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(
}
prop_info->name = impl()->GetSymbol();
if (prop_info->position == PropertyPosition::kObjectLiteral ||
prop_info->is_static ||
(!allow_harmony_private_methods() &&
(IsAccessor(prop_info->kind) ||
prop_info->kind == ParsePropertyKind::kMethod))) {
......@@ -2119,10 +2118,6 @@ ParserBase<Impl>::ParseClassPropertyDefinition(ClassInfo* class_info,
prop_info->name = impl()->GetSymbol();
name_expression =
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 {
prop_info->is_static = true;
name_expression = ParseProperty(prop_info);
......@@ -2150,22 +2145,27 @@ ParserBase<Impl>::ParseClassPropertyDefinition(ClassInfo* class_info,
// name as an uninitialized field.
if (allow_harmony_public_fields() || allow_harmony_private_fields()) {
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()) {
ReportUnexpectedToken(Next());
return impl()->NullLiteralProperty();
}
if (!prop_info->is_computed_name) {
CheckClassFieldName(prop_info->name, prop_info->is_static);
}
ExpressionT initializer = ParseMemberInitializer(
class_info, property_beg_pos, prop_info->is_static);
ExpectSemicolon();
ClassLiteralPropertyT result = factory()->NewClassLiteralProperty(
name_expression, initializer, ClassLiteralProperty::FIELD,
prop_info->is_static, prop_info->is_computed_name,
prop_info->is_private);
impl()->SetFunctionNameFromPropertyName(result, prop_info->name);
return result;
} else {
......@@ -4210,8 +4210,9 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseClassLiteral(
prop_info.is_computed_name) {
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) {
DCHECK(!prop_info.is_private);
class_info.computed_field_count++;
}
is_constructor &= class_info.has_seen_constructor;
......
......@@ -3071,7 +3071,6 @@ void Parser::DeclareClassProperty(const AstRawString* class_name,
if (is_static) {
DCHECK(allow_harmony_static_fields());
DCHECK_EQ(kind, ClassLiteralProperty::FIELD);
DCHECK(!is_private);
class_info->static_fields->Add(property, zone());
} else {
class_info->instance_fields->Add(property, zone());
......
......@@ -5698,7 +5698,7 @@ TEST(PrivateClassFieldsErrors) {
private_fields, arraysize(private_fields));
}
TEST(PrivateStaticClassFieldsErrors) {
TEST(PrivateStaticClassFieldsNoErrors) {
// clang-format off
// Tests proposed class fields syntax.
const char* context_data[][2] = {{"(class {", "});"},
......@@ -5719,6 +5719,71 @@ TEST(PrivateStaticClassFieldsErrors) {
"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; b",
"static #['a'] = 0; #b",
......@@ -5743,6 +5808,14 @@ TEST(PrivateStaticClassFieldsErrors) {
"static #*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
"static #a() { }",
"static get #a() { }",
......@@ -5752,16 +5825,6 @@ TEST(PrivateStaticClassFieldsErrors) {
"static async *#a() { }",
// 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 b",
"static #['a'] = 0\n #b",
......@@ -5773,27 +5836,34 @@ TEST(PrivateStaticClassFieldsErrors) {
"static #['a']\n *b(){}",
"static #['a']\n ['b'](){}",
"static #a = function t() { arguments; }",
"static #a = () => function t() { arguments; }",
// ASI requires a linebreak
"static #a b",
"static #a = 0 b",
// ASI edge cases
"static #a\n get",
"static #get\n *a(){}",
"static #a\n static",
// ASI requires that the next token is not part of any legal production
"static #a = 0\n *b(){}",
"static #a = 0\n ['b'](){}",
"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
"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",
"#constructor",
"#constructor = function() {}",
"foo() { delete this.#a }",
"foo() { delete this.x.#a }",
"foo() { delete this.x().#a }",
"foo() { delete f.#a }",
"foo() { delete f.x.#a }",
"foo() { delete f.x().#a }",
nullptr
};
// clang-format on
......
......@@ -44,6 +44,8 @@ from testrunner.outproc import test262
FEATURE_FLAGS = {
'class-fields-public': '--harmony-public-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.flatMap': '--harmony-array-flat',
'String.prototype.matchAll': '--harmony-string-matchall',
......@@ -60,9 +62,7 @@ FEATURE_FLAGS = {
'Object.fromEntries': '--harmony-object-from-entries',
}
SKIPPED_FEATURES = set(['class-fields-private',
'class-static-fields-private',
'class-methods-private',
SKIPPED_FEATURES = set(['class-methods-private',
'class-static-methods-private',
'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