[class] Parse static private fields
Bug: v8:5368 Change-Id: I0f6edc028baf009b81612ecc4be9a70c3621bc4e Reviewed-on: https://chromium-review.googlesource.com/c/1385528 Reviewed-by: Adam Klein <adamk@chromium.org> Commit-Queue: Sathya Gunasekaran <gsathya@chromium.org> Cr-Commit-Position: refs/heads/master@{#58416}
This commit is contained in:
parent
66d26a359f
commit
15a7059412
@ -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'](){}",
|
||||
|
||||
// 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",
|
||||
"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",
|
||||
|
||||
"#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'])
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user