Commit df12eb19 authored by Joyee Cheung's avatar Joyee Cheung Committed by Commit Bot

[class] implement private accessors

This patch implements the access of private accessors by loading the
referenced component from the AccessorPair associated with private
name variables. It also makes the error messages for invalid kind
of private accessor access more specific.

Bug: v8:8330
Design doc: https://docs.google.com/document/d/10W4begYfs7lmldSqBoQBBt_BKamgT8igqxF9u50RGrI/edit

Change-Id: I6d441cffb85f8d9cd0417ec9b6ae20f3e34ef418
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1695205Reviewed-by: 's avatarRoss McIlroy <rmcilroy@chromium.org>
Commit-Queue: Joyee Cheung <joyee@igalia.com>
Cr-Commit-Position: refs/heads/master@{#63474}
parent bdcc7502
...@@ -413,11 +413,15 @@ namespace internal { ...@@ -413,11 +413,15 @@ namespace internal {
T(InvalidOrUnexpectedToken, "Invalid or unexpected token") \ T(InvalidOrUnexpectedToken, "Invalid or unexpected token") \
T(InvalidPrivateFieldResolution, \ T(InvalidPrivateFieldResolution, \
"Private field '%' must be declared in an enclosing class") \ "Private field '%' must be declared in an enclosing class") \
T(InvalidPrivateFieldRead, \ T(InvalidPrivateMemberRead, \
"Read of private field % from an object which did not contain the field") \ "Cannot read private member % from an object whose class did not declare " \
T(InvalidPrivateFieldWrite, \ "it") \
"Write of private field % to an object which did not contain the field") \ T(InvalidPrivateMemberWrite, \
"Cannot write private member % to an object whose class did not declare " \
"it") \
T(InvalidPrivateMethodWrite, "Private method '%' is not writable") \ T(InvalidPrivateMethodWrite, "Private method '%' is not writable") \
T(InvalidPrivateGetterAccess, "'%' was defined without a getter") \
T(InvalidPrivateSetterAccess, "'%' was defined without a setter") \
T(JsonParseUnexpectedEOS, "Unexpected end of JSON input") \ T(JsonParseUnexpectedEOS, "Unexpected end of JSON input") \
T(JsonParseUnexpectedToken, "Unexpected token % in JSON at position %") \ T(JsonParseUnexpectedToken, "Unexpected token % in JSON at position %") \
T(JsonParseUnexpectedTokenNumber, "Unexpected number in JSON at position %") \ T(JsonParseUnexpectedTokenNumber, "Unexpected number in JSON at position %") \
......
...@@ -412,7 +412,7 @@ MaybeHandle<Object> LoadIC::Load(Handle<Object> object, Handle<Name> name) { ...@@ -412,7 +412,7 @@ MaybeHandle<Object> LoadIC::Load(Handle<Object> object, Handle<Name> name) {
if (name->IsPrivateName() && !it.IsFound()) { if (name->IsPrivateName() && !it.IsFound()) {
Handle<String> name_string(String::cast(Symbol::cast(*name).name()), Handle<String> name_string(String::cast(Symbol::cast(*name).name()),
isolate()); isolate());
return TypeError(MessageTemplate::kInvalidPrivateFieldRead, object, return TypeError(MessageTemplate::kInvalidPrivateMemberRead, object,
name_string); name_string);
} }
...@@ -1411,7 +1411,7 @@ MaybeHandle<Object> StoreIC::Store(Handle<Object> object, Handle<Name> name, ...@@ -1411,7 +1411,7 @@ MaybeHandle<Object> StoreIC::Store(Handle<Object> object, Handle<Name> name,
if (name->IsPrivateName() && !it.IsFound()) { if (name->IsPrivateName() && !it.IsFound()) {
Handle<String> name_string(String::cast(Symbol::cast(*name).name()), Handle<String> name_string(String::cast(Symbol::cast(*name).name()),
isolate()); isolate());
return TypeError(MessageTemplate::kInvalidPrivateFieldWrite, object, return TypeError(MessageTemplate::kInvalidPrivateMemberWrite, object,
name_string); name_string);
} }
......
...@@ -2329,12 +2329,13 @@ void BytecodeGenerator::VisitInitializeClassMembersStatement( ...@@ -2329,12 +2329,13 @@ void BytecodeGenerator::VisitInitializeClassMembersStatement(
} }
} }
void BytecodeGenerator::BuildThrowPrivateMethodWriteError( void BytecodeGenerator::BuildInvalidPropertyAccess(MessageTemplate tmpl,
const AstRawString* name) { Property* property) {
RegisterAllocationScope register_scope(this); RegisterAllocationScope register_scope(this);
const AstRawString* name = property->key()->AsVariableProxy()->raw_name();
RegisterList args = register_allocator()->NewRegisterList(2); RegisterList args = register_allocator()->NewRegisterList(2);
builder() builder()
->LoadLiteral(Smi::FromEnum(MessageTemplate::kInvalidPrivateMethodWrite)) ->LoadLiteral(Smi::FromEnum(tmpl))
.StoreAccumulatorInRegister(args[0]) .StoreAccumulatorInRegister(args[0])
.LoadLiteral(name) .LoadLiteral(name)
.StoreAccumulatorInRegister(args[1]) .StoreAccumulatorInRegister(args[1])
...@@ -3887,15 +3888,28 @@ void BytecodeGenerator::BuildAssignment( ...@@ -3887,15 +3888,28 @@ void BytecodeGenerator::BuildAssignment(
break; break;
} }
case PRIVATE_METHOD: { case PRIVATE_METHOD: {
BuildThrowPrivateMethodWriteError( BuildInvalidPropertyAccess(MessageTemplate::kInvalidPrivateMethodWrite,
lhs_data.expr()->AsProperty()->key()->AsVariableProxy()->raw_name()); lhs_data.expr()->AsProperty());
break;
}
case PRIVATE_GETTER_ONLY: {
BuildInvalidPropertyAccess(MessageTemplate::kInvalidPrivateSetterAccess,
lhs_data.expr()->AsProperty());
break; break;
} }
case PRIVATE_GETTER_ONLY:
case PRIVATE_SETTER_ONLY: case PRIVATE_SETTER_ONLY:
case PRIVATE_GETTER_AND_SETTER: { case PRIVATE_GETTER_AND_SETTER: {
// TODO(joyee): implement private accessors. Register value = register_allocator()->NewRegister();
return; builder()->StoreAccumulatorInRegister(value);
Property* property = lhs_data.expr()->AsProperty();
Register object = VisitForRegisterValue(property->obj());
Register key = VisitForRegisterValue(property->key());
BuildPrivateBrandCheck(property, object);
BuildPrivateSetterAccess(object, key, value);
if (!execution_result()->IsEffect()) {
builder()->LoadAccumulatorWithRegister(value);
}
break;
} }
} }
} }
...@@ -3942,16 +3956,13 @@ void BytecodeGenerator::VisitCompoundAssignment(CompoundAssignment* expr) { ...@@ -3942,16 +3956,13 @@ void BytecodeGenerator::VisitCompoundAssignment(CompoundAssignment* expr) {
lhs_data.super_property_args().Truncate(3)); lhs_data.super_property_args().Truncate(3));
break; break;
} }
case PRIVATE_METHOD: { case PRIVATE_METHOD:
BuildThrowPrivateMethodWriteError(
lhs_data.expr()->AsProperty()->key()->AsVariableProxy()->raw_name());
break;
}
case PRIVATE_SETTER_ONLY:
case PRIVATE_GETTER_ONLY: case PRIVATE_GETTER_ONLY:
case PRIVATE_SETTER_ONLY:
case PRIVATE_GETTER_AND_SETTER: { case PRIVATE_GETTER_AND_SETTER: {
// TODO(joyee): implement private accessors. // ({ #foo: name } = obj) is currently syntactically invalid.
return; UNREACHABLE();
break;
} }
} }
...@@ -4418,32 +4429,70 @@ void BytecodeGenerator::VisitPropertyLoad(Register obj, Property* property) { ...@@ -4418,32 +4429,70 @@ void BytecodeGenerator::VisitPropertyLoad(Register obj, Property* property) {
case KEYED_SUPER_PROPERTY: case KEYED_SUPER_PROPERTY:
VisitKeyedSuperPropertyLoad(property, Register::invalid_value()); VisitKeyedSuperPropertyLoad(property, Register::invalid_value());
break; break;
case PRIVATE_SETTER_ONLY: {
BuildInvalidPropertyAccess(MessageTemplate::kInvalidPrivateGetterAccess,
property);
break;
}
case PRIVATE_GETTER_ONLY:
case PRIVATE_GETTER_AND_SETTER: {
Register key = VisitForRegisterValue(property->key());
BuildPrivateBrandCheck(property, obj);
BuildPrivateGetterAccess(obj, key);
break;
}
case PRIVATE_METHOD: { case PRIVATE_METHOD: {
Variable* private_name = property->key()->AsVariableProxy()->var(); BuildPrivateBrandCheck(property, obj);
// Perform the brand check.
DCHECK(private_name->requires_brand_check());
ClassScope* scope = private_name->scope()->AsClassScope();
Variable* brand = scope->brand();
BuildVariableLoadForAccumulatorValue(brand, HoleCheckMode::kElided);
builder()->SetExpressionPosition(property);
builder()->LoadKeyedProperty(
obj, feedback_index(feedback_spec()->AddKeyedLoadICSlot()));
// In the case of private methods, property->key() is the function to be // In the case of private methods, property->key() is the function to be
// loaded (stored in a context slot), so load this directly. // loaded (stored in a context slot), so load this directly.
VisitForAccumulatorValue(property->key()); VisitForAccumulatorValue(property->key());
break; break;
} }
case PRIVATE_SETTER_ONLY:
case PRIVATE_GETTER_ONLY:
case PRIVATE_GETTER_AND_SETTER: {
// TODO(joyee): implement private accessors.
return;
}
} }
} }
void BytecodeGenerator::BuildPrivateGetterAccess(Register object,
Register accessor_pair) {
RegisterAllocationScope scope(this);
Register accessor = register_allocator()->NewRegister();
RegisterList args = register_allocator()->NewRegisterList(1);
builder()
->CallRuntime(Runtime::kLoadPrivateGetter, accessor_pair)
.StoreAccumulatorInRegister(accessor)
.MoveRegister(object, args[0])
.CallProperty(accessor, args,
feedback_index(feedback_spec()->AddCallICSlot()));
}
void BytecodeGenerator::BuildPrivateSetterAccess(Register object,
Register accessor_pair,
Register value) {
RegisterAllocationScope scope(this);
Register accessor = register_allocator()->NewRegister();
RegisterList args = register_allocator()->NewRegisterList(2);
builder()
->CallRuntime(Runtime::kLoadPrivateSetter, accessor_pair)
.StoreAccumulatorInRegister(accessor)
.MoveRegister(object, args[0])
.MoveRegister(value, args[1])
.CallProperty(accessor, args,
feedback_index(feedback_spec()->AddCallICSlot()));
}
void BytecodeGenerator::BuildPrivateBrandCheck(Property* property,
Register object) {
Variable* private_name = property->key()->AsVariableProxy()->var();
DCHECK(private_name->requires_brand_check());
ClassScope* scope = private_name->scope()->AsClassScope();
Variable* brand = scope->brand();
BuildVariableLoadForAccumulatorValue(brand, HoleCheckMode::kElided);
builder()->SetExpressionPosition(property);
builder()->LoadKeyedProperty(
object, feedback_index(feedback_spec()->AddKeyedLoadICSlot()));
}
void BytecodeGenerator::VisitPropertyLoadForRegister(Register obj, void BytecodeGenerator::VisitPropertyLoadForRegister(Register obj,
Property* expr, Property* expr,
Register destination) { Register destination) {
...@@ -5030,16 +5079,27 @@ void BytecodeGenerator::VisitCountOperation(CountOperation* expr) { ...@@ -5030,16 +5079,27 @@ void BytecodeGenerator::VisitCountOperation(CountOperation* expr) {
break; break;
} }
case PRIVATE_METHOD: { case PRIVATE_METHOD: {
BuildThrowPrivateMethodWriteError( BuildInvalidPropertyAccess(MessageTemplate::kInvalidPrivateMethodWrite,
property->key()->AsVariableProxy()->raw_name()); property);
break; return;
} }
case PRIVATE_GETTER_ONLY: case PRIVATE_GETTER_ONLY: {
case PRIVATE_SETTER_ONLY: BuildInvalidPropertyAccess(MessageTemplate::kInvalidPrivateSetterAccess,
case PRIVATE_GETTER_AND_SETTER: { property);
// TODO(joyee): implement private accessors.
return; return;
} }
case PRIVATE_SETTER_ONLY: {
BuildInvalidPropertyAccess(MessageTemplate::kInvalidPrivateGetterAccess,
property);
return;
}
case PRIVATE_GETTER_AND_SETTER: {
object = VisitForRegisterValue(property->obj());
key = VisitForRegisterValue(property->key());
BuildPrivateBrandCheck(property, object);
BuildPrivateGetterAccess(object, key);
break;
}
} }
// Save result for postfix expressions. // Save result for postfix expressions.
...@@ -5106,16 +5166,19 @@ void BytecodeGenerator::VisitCountOperation(CountOperation* expr) { ...@@ -5106,16 +5166,19 @@ void BytecodeGenerator::VisitCountOperation(CountOperation* expr) {
.CallRuntime(Runtime::kStoreKeyedToSuper, super_property_args); .CallRuntime(Runtime::kStoreKeyedToSuper, super_property_args);
break; break;
} }
case PRIVATE_SETTER_ONLY:
case PRIVATE_GETTER_ONLY:
case PRIVATE_METHOD: { case PRIVATE_METHOD: {
BuildThrowPrivateMethodWriteError( UNREACHABLE();
property->key()->AsVariableProxy()->raw_name());
break;
} }
case PRIVATE_GETTER_ONLY:
case PRIVATE_SETTER_ONLY:
case PRIVATE_GETTER_AND_SETTER: { case PRIVATE_GETTER_AND_SETTER: {
// TODO(joyee): implement private accessors. Register value = register_allocator()->NewRegister();
UNREACHABLE(); builder()->StoreAccumulatorInRegister(value);
BuildPrivateSetterAccess(object, key, value);
if (!execution_result()->IsEffect()) {
builder()->LoadAccumulatorWithRegister(value);
}
break;
} }
} }
......
...@@ -302,7 +302,11 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> { ...@@ -302,7 +302,11 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
void VisitArgumentsObject(Variable* variable); void VisitArgumentsObject(Variable* variable);
void VisitRestArgumentsArray(Variable* rest); void VisitRestArgumentsArray(Variable* rest);
void VisitCallSuper(Call* call); void VisitCallSuper(Call* call);
void BuildThrowPrivateMethodWriteError(const AstRawString* name); void BuildInvalidPropertyAccess(MessageTemplate tmpl, Property* property);
void BuildPrivateBrandCheck(Property* property, Register object);
void BuildPrivateGetterAccess(Register obj, Register access_pair);
void BuildPrivateSetterAccess(Register obj, Register access_pair,
Register value);
void BuildClassLiteral(ClassLiteral* expr, Register name); void BuildClassLiteral(ClassLiteral* expr, Register name);
void VisitClassLiteral(ClassLiteral* expr, Register name); void VisitClassLiteral(ClassLiteral* expr, Register name);
void VisitNewTargetVariable(Variable* variable); void VisitNewTargetVariable(Variable* variable);
......
...@@ -46,7 +46,7 @@ MaybeHandle<Object> Runtime::GetObjectProperty(Isolate* isolate, ...@@ -46,7 +46,7 @@ MaybeHandle<Object> Runtime::GetObjectProperty(Isolate* isolate,
Handle<Object> name_string(Symbol::cast(*key).name(), isolate); Handle<Object> name_string(Symbol::cast(*key).name(), isolate);
DCHECK(name_string->IsString()); DCHECK(name_string->IsString());
THROW_NEW_ERROR(isolate, THROW_NEW_ERROR(isolate,
NewTypeError(MessageTemplate::kInvalidPrivateFieldRead, NewTypeError(MessageTemplate::kInvalidPrivateMemberRead,
name_string, object), name_string, object),
Object); Object);
} }
...@@ -413,7 +413,7 @@ MaybeHandle<Object> Runtime::SetObjectProperty( ...@@ -413,7 +413,7 @@ MaybeHandle<Object> Runtime::SetObjectProperty(
Handle<Object> name_string(Symbol::cast(*key).name(), isolate); Handle<Object> name_string(Symbol::cast(*key).name(), isolate);
DCHECK(name_string->IsString()); DCHECK(name_string->IsString());
THROW_NEW_ERROR(isolate, THROW_NEW_ERROR(isolate,
NewTypeError(MessageTemplate::kInvalidPrivateFieldWrite, NewTypeError(MessageTemplate::kInvalidPrivateMemberWrite,
name_string, object), name_string, object),
Object); Object);
} }
......
#
# Autogenerated by generate-bytecode-expectations.
#
---
wrap: no
test function name: test
private methods: yes
---
snippet: "
class A {
get #a() { return 1; }
set #a(val) { }
constructor() {
this.#a++;
this.#a = 1;
return this.#a;
}
}
var test = A;
new test;
"
frame size: 6
parameter count: 1
bytecode array length: 95
bytecodes: [
/* 67 E> */ B(StackCheck),
B(LdaCurrentContextSlot), U8(5),
B(Star), R(1),
B(Mov), R(this), R(0),
B(CallRuntime), U16(Runtime::kAddPrivateBrand), R(0), U8(2),
/* 76 S> */ B(LdaCurrentContextSlot), U8(4),
B(Star), R(3),
B(LdaCurrentContextSlot), U8(5),
/* 81 E> */ B(LdaKeyedProperty), R(this), U8(0),
B(CallRuntime), U16(Runtime::kLoadPrivateGetter), R(3), U8(1),
B(Star), R(4),
B(CallProperty0), R(4), R(this), U8(2),
B(Inc), U8(4),
B(Star), R(4),
/* 83 E> */ B(CallRuntime), U16(Runtime::kLoadPrivateSetter), R(3), U8(1),
B(Star), R(5),
B(CallProperty1), R(5), R(this), R(4), U8(5),
/* 91 S> */ B(LdaSmi), I8(1),
B(Star), R(2),
B(LdaCurrentContextSlot), U8(4),
B(Star), R(4),
B(LdaCurrentContextSlot), U8(5),
/* 96 E> */ B(LdaKeyedProperty), R(this), U8(7),
B(CallRuntime), U16(Runtime::kLoadPrivateSetter), R(4), U8(1),
B(Star), R(5),
B(CallProperty1), R(5), R(this), R(2), U8(9),
/* 108 S> */ B(LdaCurrentContextSlot), U8(4),
B(Star), R(3),
B(LdaCurrentContextSlot), U8(5),
/* 120 E> */ B(LdaKeyedProperty), R(this), U8(11),
B(CallRuntime), U16(Runtime::kLoadPrivateGetter), R(3), U8(1),
B(Star), R(4),
B(CallProperty0), R(4), R(this), U8(13),
/* 123 S> */ B(Return),
]
constant pool: [
]
handlers: [
]
---
snippet: "
class B {
get #b() { return 1; }
constructor() { this.#b++; }
}
var test = B;
new test;
"
frame size: 4
parameter count: 1
bytecode array length: 29
bytecodes: [
/* 48 E> */ B(StackCheck),
B(LdaCurrentContextSlot), U8(5),
B(Star), R(1),
B(Mov), R(this), R(0),
B(CallRuntime), U16(Runtime::kAddPrivateBrand), R(0), U8(2),
/* 53 S> */ B(Wide), B(LdaSmi), I16(263),
B(Star), R(2),
B(LdaConstant), U8(0),
B(Star), R(3),
B(CallRuntime), U16(Runtime::kNewTypeError), R(2), U8(2),
B(Throw),
]
constant pool: [
ONE_BYTE_INTERNALIZED_STRING_TYPE ["#b"],
]
handlers: [
]
---
snippet: "
class C {
set #c(val) { }
constructor() { this.#c++; }
}
var test = C;
new test;
"
frame size: 4
parameter count: 1
bytecode array length: 29
bytecodes: [
/* 41 E> */ B(StackCheck),
B(LdaCurrentContextSlot), U8(5),
B(Star), R(1),
B(Mov), R(this), R(0),
B(CallRuntime), U16(Runtime::kAddPrivateBrand), R(0), U8(2),
/* 46 S> */ B(Wide), B(LdaSmi), I16(262),
B(Star), R(2),
B(LdaConstant), U8(0),
B(Star), R(3),
B(CallRuntime), U16(Runtime::kNewTypeError), R(2), U8(2),
B(Throw),
]
constant pool: [
ONE_BYTE_INTERNALIZED_STRING_TYPE ["#c"],
]
handlers: [
]
---
snippet: "
class D {
get #d() { return 1; }
constructor() { this.#d = 1; }
}
var test = D;
new test;
"
frame size: 4
parameter count: 1
bytecode array length: 29
bytecodes: [
/* 48 E> */ B(StackCheck),
B(LdaCurrentContextSlot), U8(5),
B(Star), R(1),
B(Mov), R(this), R(0),
B(CallRuntime), U16(Runtime::kAddPrivateBrand), R(0), U8(2),
/* 53 S> */ B(Wide), B(LdaSmi), I16(263),
B(Star), R(2),
B(LdaConstant), U8(0),
B(Star), R(3),
/* 61 E> */ B(CallRuntime), U16(Runtime::kNewTypeError), R(2), U8(2),
B(Throw),
]
constant pool: [
ONE_BYTE_INTERNALIZED_STRING_TYPE ["#d"],
]
handlers: [
]
---
snippet: "
class E {
set #e(val) { }
constructor() { this.#e; }
}
var test = E;
new test;
"
frame size: 5
parameter count: 1
bytecode array length: 29
bytecodes: [
/* 41 E> */ B(StackCheck),
B(LdaCurrentContextSlot), U8(5),
B(Star), R(1),
B(Mov), R(this), R(0),
B(CallRuntime), U16(Runtime::kAddPrivateBrand), R(0), U8(2),
/* 46 S> */ B(Wide), B(LdaSmi), I16(262),
B(Star), R(3),
B(LdaConstant), U8(0),
B(Star), R(4),
B(CallRuntime), U16(Runtime::kNewTypeError), R(3), U8(2),
B(Throw),
]
constant pool: [
ONE_BYTE_INTERNALIZED_STRING_TYPE ["#e"],
]
handlers: [
]
#
# Autogenerated by generate-bytecode-expectations.
#
---
wrap: no
test function name: test
private methods: yes
---
snippet: "
class A {
#a() { return 1; }
constructor() { return this.#a(); }
}
var test = A;
new A;
"
frame size: 3
parameter count: 1
bytecode array length: 28
bytecodes: [
/* 44 E> */ B(StackCheck),
B(LdaCurrentContextSlot), U8(5),
B(Star), R(1),
B(Mov), R(this), R(0),
B(CallRuntime), U16(Runtime::kAddPrivateBrand), R(0), U8(2),
/* 49 S> */ B(LdaCurrentContextSlot), U8(5),
/* 61 E> */ B(LdaKeyedProperty), R(this), U8(0),
B(LdaCurrentContextSlot), U8(4),
B(Star), R(2),
/* 63 E> */ B(CallAnyReceiver), R(2), R(this), U8(1), U8(2),
/* 66 S> */ B(Return),
]
constant pool: [
]
handlers: [
]
---
snippet: "
class B {
#b() { return 1; }
constructor() { this.#b = 1; }
}
var test = B;
new test;
"
frame size: 4
parameter count: 1
bytecode array length: 29
bytecodes: [
/* 44 E> */ B(StackCheck),
B(LdaCurrentContextSlot), U8(5),
B(Star), R(1),
B(Mov), R(this), R(0),
B(CallRuntime), U16(Runtime::kAddPrivateBrand), R(0), U8(2),
/* 49 S> */ B(Wide), B(LdaSmi), I16(261),
B(Star), R(2),
B(LdaConstant), U8(0),
B(Star), R(3),
/* 57 E> */ B(CallRuntime), U16(Runtime::kNewTypeError), R(2), U8(2),
B(Throw),
]
constant pool: [
ONE_BYTE_INTERNALIZED_STRING_TYPE ["#b"],
]
handlers: [
]
---
snippet: "
class C {
#c() { return 1; }
constructor() { this.#c++; }
}
var test = C;
new test;
"
frame size: 4
parameter count: 1
bytecode array length: 29
bytecodes: [
/* 44 E> */ B(StackCheck),
B(LdaCurrentContextSlot), U8(5),
B(Star), R(1),
B(Mov), R(this), R(0),
B(CallRuntime), U16(Runtime::kAddPrivateBrand), R(0), U8(2),
/* 49 S> */ B(Wide), B(LdaSmi), I16(261),
B(Star), R(2),
B(LdaConstant), U8(0),
B(Star), R(3),
B(CallRuntime), U16(Runtime::kNewTypeError), R(2), U8(2),
B(Throw),
]
constant pool: [
ONE_BYTE_INTERNALIZED_STRING_TYPE ["#c"],
]
handlers: [
]
...@@ -11,57 +11,43 @@ snippet: " ...@@ -11,57 +11,43 @@ snippet: "
{ {
class A { class A {
#a() { return 1; } #a() { return 1; }
callA() { return this.#a(); }
} }
const a = new A;
a.callA();
} }
" "
frame size: 9 frame size: 7
parameter count: 1 parameter count: 1
bytecode array length: 80 bytecode array length: 55
bytecodes: [ bytecodes: [
/* 30 E> */ B(StackCheck), /* 30 E> */ B(StackCheck),
B(CreateBlockContext), U8(0), B(CreateBlockContext), U8(0),
B(PushContext), R(3), B(PushContext), R(2),
B(LdaTheHole), B(LdaTheHole),
B(Star), R(7), B(Star), R(6),
B(CreateClosure), U8(2), U8(0), U8(2), B(CreateClosure), U8(2), U8(0), U8(2),
B(Star), R(4), B(Star), R(3),
B(LdaConstant), U8(1), B(LdaConstant), U8(1),
B(Star), R(5), B(Star), R(4),
B(CreateClosure), U8(3), U8(1), U8(2), B(CreateClosure), U8(3), U8(1), U8(2),
B(StaCurrentContextSlot), U8(4), B(StaCurrentContextSlot), U8(4),
B(CreateClosure), U8(4), U8(2), U8(2), B(Mov), R(3), R(5),
B(Star), R(8), B(CallRuntime), U16(Runtime::kDefineClass), R(4), U8(3),
B(Mov), R(4), R(6), B(Star), R(4),
B(CallRuntime), U16(Runtime::kDefineClass), R(5), U8(4), B(Mov), R(5), R(1),
B(LdaConstant), U8(4),
B(Star), R(5), B(Star), R(5),
B(Mov), R(6), R(2), B(CallRuntime), U16(Runtime::kCreatePrivateNameSymbol), R(5), U8(1),
B(LdaConstant), U8(5),
B(Star), R(6),
B(CallRuntime), U16(Runtime::kCreatePrivateNameSymbol), R(6), U8(1),
B(StaCurrentContextSlot), U8(5), B(StaCurrentContextSlot), U8(5),
B(PopContext), R(3), B(PopContext), R(2),
B(Mov), R(2), R(0), B(Mov), R(1), R(0),
/* 122 S> */ B(Ldar), R(0),
/* 122 E> */ B(Construct), R(0), R(0), U8(0), U8(0),
B(Star), R(1),
/* 133 S> */ B(LdaNamedProperty), R(1), U8(6), U8(2),
B(Star), R(3),
/* 133 E> */ B(CallProperty0), R(3), R(1), U8(4),
B(LdaUndefined), B(LdaUndefined),
/* 144 S> */ B(Return), /* 77 S> */ B(Return),
] ]
constant pool: [ constant pool: [
SCOPE_INFO_TYPE, SCOPE_INFO_TYPE,
FIXED_ARRAY_TYPE, FIXED_ARRAY_TYPE,
SHARED_FUNCTION_INFO_TYPE, SHARED_FUNCTION_INFO_TYPE,
SHARED_FUNCTION_INFO_TYPE, SHARED_FUNCTION_INFO_TYPE,
SHARED_FUNCTION_INFO_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["A"], ONE_BYTE_INTERNALIZED_STRING_TYPE ["A"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["callA"],
] ]
handlers: [ handlers: [
] ]
...@@ -71,89 +57,70 @@ snippet: " ...@@ -71,89 +57,70 @@ snippet: "
{ {
class D { class D {
#d() { return 1; } #d() { return 1; }
callD() { return this.#d(); }
} }
class E extends D { class E extends D {
#e() { return 2; } #e() { return 2; }
callE() { return this.callD() + this.#e(); }
} }
const e = new E;
e.callE();
} }
" "
frame size: 11 frame size: 9
parameter count: 1 parameter count: 1
bytecode array length: 138 bytecode array length: 107
bytecodes: [ bytecodes: [
/* 30 E> */ B(StackCheck), /* 30 E> */ B(StackCheck),
B(CreateBlockContext), U8(0), B(CreateBlockContext), U8(0),
B(PushContext), R(5), B(PushContext), R(4),
B(LdaTheHole), B(LdaTheHole),
B(Star), R(9), B(Star), R(8),
B(CreateClosure), U8(2), U8(0), U8(2), B(CreateClosure), U8(2), U8(0), U8(2),
B(Star), R(6), B(Star), R(5),
B(LdaConstant), U8(1), B(LdaConstant), U8(1),
B(Star), R(7), B(Star), R(6),
B(CreateClosure), U8(3), U8(1), U8(2), B(CreateClosure), U8(3), U8(1), U8(2),
B(StaCurrentContextSlot), U8(4), B(StaCurrentContextSlot), U8(4),
B(CreateClosure), U8(4), U8(2), U8(2), B(Mov), R(5), R(7),
B(Star), R(10), B(CallRuntime), U16(Runtime::kDefineClass), R(6), U8(3),
B(Mov), R(6), R(8), B(Star), R(6),
B(CallRuntime), U16(Runtime::kDefineClass), R(7), U8(4), B(Mov), R(7), R(3),
B(LdaConstant), U8(4),
B(Star), R(7), B(Star), R(7),
B(Mov), R(8), R(4), B(CallRuntime), U16(Runtime::kCreatePrivateNameSymbol), R(7), U8(1),
B(LdaConstant), U8(5),
B(Star), R(8),
B(CallRuntime), U16(Runtime::kCreatePrivateNameSymbol), R(8), U8(1),
B(StaCurrentContextSlot), U8(5), B(StaCurrentContextSlot), U8(5),
B(PopContext), R(5), B(PopContext), R(4),
B(Mov), R(4), R(0), B(Mov), R(3), R(0),
/* 38 E> */ B(CreateBlockContext), U8(6), /* 38 E> */ B(CreateBlockContext), U8(5),
B(PushContext), R(5), B(PushContext), R(4),
/* 128 E> */ B(CreateClosure), U8(8), U8(3), U8(2), /* 93 E> */ B(CreateClosure), U8(7), U8(2), U8(2),
B(Star), R(5),
B(LdaConstant), U8(6),
B(Star), R(6), B(Star), R(6),
B(LdaConstant), U8(7), B(CreateClosure), U8(8), U8(3), U8(2),
B(Star), R(7),
B(CreateClosure), U8(9), U8(4), U8(2),
B(StaCurrentContextSlot), U8(4), B(StaCurrentContextSlot), U8(4),
B(CreateClosure), U8(10), U8(5), U8(2), B(Mov), R(5), R(7),
B(Star), R(10), B(Mov), R(3), R(8),
B(Mov), R(6), R(8), B(CallRuntime), U16(Runtime::kDefineClass), R(6), U8(3),
B(Mov), R(4), R(9), B(Star), R(6),
B(CallRuntime), U16(Runtime::kDefineClass), R(7), U8(4), B(Mov), R(7), R(2),
B(LdaConstant), U8(9),
B(Star), R(7), B(Star), R(7),
B(Mov), R(8), R(3), B(CallRuntime), U16(Runtime::kCreatePrivateNameSymbol), R(7), U8(1),
B(LdaConstant), U8(11),
B(Star), R(8),
B(CallRuntime), U16(Runtime::kCreatePrivateNameSymbol), R(8), U8(1),
B(StaCurrentContextSlot), U8(5), B(StaCurrentContextSlot), U8(5),
B(PopContext), R(5), B(PopContext), R(4),
B(Mov), R(3), R(1), B(Mov), R(2), R(1),
/* 221 S> */ B(Ldar), R(1),
/* 221 E> */ B(Construct), R(1), R(0), U8(0), U8(0),
B(Star), R(2),
/* 232 S> */ B(LdaNamedProperty), R(2), U8(12), U8(2),
B(Star), R(5),
/* 232 E> */ B(CallProperty0), R(5), R(2), U8(4),
B(LdaUndefined), B(LdaUndefined),
/* 243 S> */ B(Return), /* 126 S> */ B(Return),
] ]
constant pool: [ constant pool: [
SCOPE_INFO_TYPE, SCOPE_INFO_TYPE,
FIXED_ARRAY_TYPE, FIXED_ARRAY_TYPE,
SHARED_FUNCTION_INFO_TYPE, SHARED_FUNCTION_INFO_TYPE,
SHARED_FUNCTION_INFO_TYPE, SHARED_FUNCTION_INFO_TYPE,
SHARED_FUNCTION_INFO_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["D"], ONE_BYTE_INTERNALIZED_STRING_TYPE ["D"],
SCOPE_INFO_TYPE, SCOPE_INFO_TYPE,
FIXED_ARRAY_TYPE, FIXED_ARRAY_TYPE,
SHARED_FUNCTION_INFO_TYPE, SHARED_FUNCTION_INFO_TYPE,
SHARED_FUNCTION_INFO_TYPE, SHARED_FUNCTION_INFO_TYPE,
SHARED_FUNCTION_INFO_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["E"], ONE_BYTE_INTERNALIZED_STRING_TYPE ["E"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["callE"],
] ]
handlers: [ handlers: [
] ]
...@@ -164,14 +131,12 @@ snippet: " ...@@ -164,14 +131,12 @@ snippet: "
class A { foo() {} } class A { foo() {} }
class C extends A { class C extends A {
#m() { return super.foo; } #m() { return super.foo; }
fn() { return this.#m(); }
} }
new C().fn();
} }
" "
frame size: 10 frame size: 10
parameter count: 1 parameter count: 1
bytecode array length: 131 bytecode array length: 106
bytecodes: [ bytecodes: [
/* 30 E> */ B(StackCheck), /* 30 E> */ B(StackCheck),
B(CreateBlockContext), U8(0), B(CreateBlockContext), U8(0),
...@@ -198,31 +163,23 @@ bytecodes: [ ...@@ -198,31 +163,23 @@ bytecodes: [
B(Star), R(6), B(Star), R(6),
B(CreateClosure), U8(7), U8(3), U8(2), B(CreateClosure), U8(7), U8(3), U8(2),
B(StaCurrentContextSlot), U8(4), B(StaCurrentContextSlot), U8(4),
B(CreateClosure), U8(8), U8(4), U8(2),
B(Star), R(9),
B(Mov), R(5), R(7), B(Mov), R(5), R(7),
B(Mov), R(3), R(8), B(Mov), R(3), R(8),
B(CallRuntime), U16(Runtime::kDefineClass), R(6), U8(4), B(CallRuntime), U16(Runtime::kDefineClass), R(6), U8(3),
B(Star), R(6), B(Star), R(6),
B(Mov), R(7), R(2), B(Mov), R(7), R(2),
B(LdaConstant), U8(9), B(LdaConstant), U8(8),
B(Star), R(7), B(Star), R(7),
B(CallRuntime), U16(Runtime::kCreatePrivateNameSymbol), R(7), U8(1), B(CallRuntime), U16(Runtime::kCreatePrivateNameSymbol), R(7), U8(1),
B(StaCurrentContextSlot), U8(5), B(StaCurrentContextSlot), U8(5),
B(LdaCurrentContextSlot), U8(4), B(LdaCurrentContextSlot), U8(4),
B(Star), R(8), B(Star), R(8),
B(Ldar), R(6), B(Ldar), R(6),
B(StaNamedProperty), R(8), U8(10), U8(0), B(StaNamedProperty), R(8), U8(9), U8(0),
B(PopContext), R(4), B(PopContext), R(4),
B(Mov), R(2), R(1), B(Mov), R(2), R(1),
/* 149 S> */ B(Ldar), R(1),
/* 149 E> */ B(Construct), R(5), R(0), U8(0), U8(2),
B(Star), R(5),
/* 157 E> */ B(LdaNamedProperty), R(5), U8(11), U8(4),
B(Star), R(4),
/* 157 E> */ B(CallProperty0), R(4), R(5), U8(6),
B(LdaUndefined), B(LdaUndefined),
/* 165 S> */ B(Return), /* 118 S> */ B(Return),
] ]
constant pool: [ constant pool: [
SCOPE_INFO_TYPE, SCOPE_INFO_TYPE,
...@@ -233,10 +190,8 @@ constant pool: [ ...@@ -233,10 +190,8 @@ constant pool: [
FIXED_ARRAY_TYPE, FIXED_ARRAY_TYPE,
SHARED_FUNCTION_INFO_TYPE, SHARED_FUNCTION_INFO_TYPE,
SHARED_FUNCTION_INFO_TYPE, SHARED_FUNCTION_INFO_TYPE,
SHARED_FUNCTION_INFO_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["C"], ONE_BYTE_INTERNALIZED_STRING_TYPE ["C"],
SYMBOL_TYPE, SYMBOL_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["fn"],
] ]
handlers: [ handlers: [
] ]
......
...@@ -2758,7 +2758,7 @@ TEST(PrivateClassFields) { ...@@ -2758,7 +2758,7 @@ TEST(PrivateClassFields) {
LoadGolden("PrivateClassFields.golden"))); LoadGolden("PrivateClassFields.golden")));
} }
TEST(PrivateMethods) { TEST(PrivateMethodDeclaration) {
bool old_methods_flag = i::FLAG_harmony_private_methods; bool old_methods_flag = i::FLAG_harmony_private_methods;
i::FLAG_harmony_private_methods = true; i::FLAG_harmony_private_methods = true;
InitializedIgnitionHandleScope scope; InitializedIgnitionHandleScope scope;
...@@ -2768,43 +2768,124 @@ TEST(PrivateMethods) { ...@@ -2768,43 +2768,124 @@ TEST(PrivateMethods) {
"{\n" "{\n"
" class A {\n" " class A {\n"
" #a() { return 1; }\n" " #a() { return 1; }\n"
" callA() { return this.#a(); }\n"
" }\n" " }\n"
"\n"
" const a = new A;\n"
" a.callA();\n"
"}\n", "}\n",
"{\n" "{\n"
" class D {\n" " class D {\n"
" #d() { return 1; }\n" " #d() { return 1; }\n"
" callD() { return this.#d(); }\n"
" }\n" " }\n"
"\n"
" class E extends D {\n" " class E extends D {\n"
" #e() { return 2; }\n" " #e() { return 2; }\n"
" callE() { return this.callD() + this.#e(); }\n"
" }\n" " }\n"
"\n"
" const e = new E;\n"
" e.callE();\n"
"}\n", "}\n",
"{\n" "{\n"
" class A { foo() {} }\n" " class A { foo() {} }\n"
" class C extends A {\n" " class C extends A {\n"
" #m() { return super.foo; }\n" " #m() { return super.foo; }\n"
" fn() { return this.#m(); }\n"
" }\n" " }\n"
" new C().fn();\n"
"}\n"}; "}\n"};
CHECK(CompareTexts(BuildActual(printer, snippets), CHECK(CompareTexts(BuildActual(printer, snippets),
LoadGolden("PrivateMethods.golden"))); LoadGolden("PrivateMethodDeclaration.golden")));
i::FLAG_harmony_private_methods = old_methods_flag;
}
TEST(PrivateMethodAccess) {
bool old_methods_flag = i::FLAG_harmony_private_methods;
i::FLAG_harmony_private_methods = true;
InitializedIgnitionHandleScope scope;
BytecodeExpectationsPrinter printer(CcTest::isolate());
printer.set_wrap(false);
printer.set_test_function_name("test");
const char* snippets[] = {
"class A {\n"
" #a() { return 1; }\n"
" constructor() { return this.#a(); }\n"
"}\n"
"\n"
"var test = A;\n"
"new A;\n",
"class B {\n"
" #b() { return 1; }\n"
" constructor() { this.#b = 1; }\n"
"}\n"
"\n"
"var test = B;\n"
"new test;\n",
"class C {\n"
" #c() { return 1; }\n"
" constructor() { this.#c++; }\n"
"}\n"
"\n"
"var test = C;\n"
"new test;\n"};
CHECK(CompareTexts(BuildActual(printer, snippets),
LoadGolden("PrivateMethodAccess.golden")));
i::FLAG_harmony_private_methods = old_methods_flag;
}
TEST(PrivateAccessorAccess) {
bool old_methods_flag = i::FLAG_harmony_private_methods;
i::FLAG_harmony_private_methods = true;
InitializedIgnitionHandleScope scope;
BytecodeExpectationsPrinter printer(CcTest::isolate());
printer.set_wrap(false);
printer.set_test_function_name("test");
const char* snippets[] = {
"class A {\n"
" get #a() { return 1; }\n"
" set #a(val) { }\n"
"\n"
" constructor() {\n"
" this.#a++;\n"
" this.#a = 1;\n"
" return this.#a;\n"
" }\n"
"}\n"
"var test = A;\n"
"new test;\n",
"class B {\n"
" get #b() { return 1; }\n"
" constructor() { this.#b++; }\n"
"}\n"
"var test = B;\n"
"new test;\n",
"class C {\n"
" set #c(val) { }\n"
" constructor() { this.#c++; }\n"
"}\n"
"var test = C;\n"
"new test;\n",
"class D {\n"
" get #d() { return 1; }\n"
" constructor() { this.#d = 1; }\n"
"}\n"
"var test = D;\n"
"new test;\n",
"class E {\n"
" set #e(val) { }\n"
" constructor() { this.#e; }\n"
"}\n"
"var test = E;\n"
"new test;\n"};
CHECK(CompareTexts(BuildActual(printer, snippets),
LoadGolden("PrivateAccessorAccess.golden")));
i::FLAG_harmony_private_methods = old_methods_flag; i::FLAG_harmony_private_methods = old_methods_flag;
} }
TEST(PrivateAccessors) { TEST(PrivateAccessorDeclaration) {
bool old_methods_flag = i::FLAG_harmony_private_methods; bool old_methods_flag = i::FLAG_harmony_private_methods;
i::FLAG_harmony_private_methods = true; i::FLAG_harmony_private_methods = true;
InitializedIgnitionHandleScope scope; InitializedIgnitionHandleScope scope;
...@@ -2859,7 +2940,7 @@ TEST(PrivateAccessors) { ...@@ -2859,7 +2940,7 @@ TEST(PrivateAccessors) {
"}\n"}; "}\n"};
CHECK(CompareTexts(BuildActual(printer, snippets), CHECK(CompareTexts(BuildActual(printer, snippets),
LoadGolden("PrivateAccessors.golden"))); LoadGolden("PrivateAccessorDeclaration.golden")));
i::FLAG_harmony_private_methods = old_methods_flag; i::FLAG_harmony_private_methods = old_methods_flag;
} }
......
// Copyright 2019 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --harmony-private-methods
class C {
set #foo(val) {}
constructor() {
this.#foo++;
}
}
new C();
# Copyright 2019 the V8 project authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
*%(basename)s:10: TypeError: '#foo' was defined without a getter
this.#foo++;
^
TypeError: '#foo' was defined without a getter
at new C (*%(basename)s:10:5)
at *%(basename)s:14:1
// Copyright 2019 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --harmony-private-methods
class C {
set #a(val) {}
setA(obj, val) { obj.#a = val; }
constructor() {
class D {
get #a() {}
}
this.setA(new D(), 1);
}
}
new C;
# Copyright 2019 the V8 project authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
*%(basename)s:9: TypeError: Cannot read private member C from an object whose class did not declare it
setA(obj, val) { obj.#a = val; }
^
TypeError: Cannot read private member C from an object whose class did not declare it
at C.setA (*%(basename)s:9:24)
at new C (*%(basename)s:15:10)
at *%(basename)s:19:1
\ No newline at end of file
// Copyright 2019 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --harmony-private-methods
class C {
set #a(val) {}
constructor() {
const a = this.#a;
}
}
new C;
# Copyright 2019 the V8 project authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
*%(basename)s:10: TypeError: '#a' was defined without a getter
const a = this.#a;
^
TypeError: '#a' was defined without a getter
at new C (*%(basename)s:10:15)
at *%(basename)s:13:1
// Copyright 2019 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --harmony-private-methods
class C {
get #a() {}
constructor() {
this.#a = 1;
}
}
new C;
# Copyright 2019 the V8 project authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
*%(basename)s:10: TypeError: '#a' was defined without a setter
this.#a = 1;
^
TypeError: '#a' was defined without a setter
at new C (*%(basename)s:10:13)
at *%(basename)s:13:1
// Copyright 2019 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --harmony-private-methods
class C {
get #foo() {}
constructor() {
this.#foo++;
}
}
new C();
# Copyright 2019 the V8 project authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
*%(basename)s:10: TypeError: '#foo' was defined without a setter
this.#foo++;
^
TypeError: '#foo' was defined without a setter
at new C (*%(basename)s:10:5)
at *%(basename)s:14:1
// Copyright 2019 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --harmony-private-methods
class C {
get #a() {}
getA(obj) { return obj.#a; }
constructor() {
class D {
set #a(val) {}
}
this.getA(new D());
}
}
new C;
# Copyright 2019 the V8 project authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
*%(basename)s:9: TypeError: Cannot read private member C from an object whose class did not declare it
getA(obj) { return obj.#a; }
^
TypeError: Cannot read private member C from an object whose class did not declare it
at C.getA (*%(basename)s:9:26)
at new C (*%(basename)s:15:10)
at *%(basename)s:19:1
// Copyright 2019 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --harmony-private-methods
class C {
get #a() {}
constructor() {
this.#a = 1;
}
}
new C;
# Copyright 2019 the V8 project authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
*%(basename)s:10: TypeError: '#a' was defined without a setter
this.#a = 1;
^
TypeError: '#a' was defined without a setter
at new C (*%(basename)s:10:13)
at *%(basename)s:13:1
\ No newline at end of file
*%(basename)s:9: TypeError: Read of private field #a from an object which did not contain the field *%(basename)s:9: TypeError: Cannot read private member #a from an object whose class did not declare it
[o.#a](){} [o.#a](){}
^ ^
TypeError: Read of private field #a from an object which did not contain the field TypeError: Cannot read private member #a from an object whose class did not declare it
at *%(basename)s:9:8 at *%(basename)s:9:8
*%(basename)s:8: TypeError: Write of private field #x to an object which did not contain the field *%(basename)s:8: TypeError: Cannot write private member #x to an object whose class did not declare it
({}).#x = 1; ({}).#x = 1;
^ ^
TypeError: Write of private field #x to an object which did not contain the field TypeError: Cannot write private member #x to an object whose class did not declare it
at new X (*%(basename)s:8:13) at new X (*%(basename)s:8:13)
at *%(basename)s:12:1 at *%(basename)s:12:1
\ No newline at end of file
*%(basename)s:7: TypeError: Read of private field #x from an object which did not contain the field *%(basename)s:7: TypeError: Cannot read private member #x from an object whose class did not declare it
eq(o) { return this.#x === o.#x; } eq(o) { return this.#x === o.#x; }
^ ^
TypeError: Read of private field #x from an object which did not contain the field TypeError: Cannot read private member #x from an object whose class did not declare it
at X.eq (*%(basename)s:7:32) at X.eq (*%(basename)s:7:32)
at *%(basename)s:10:9 at *%(basename)s:10:9
\ No newline at end of file
*%(basename)s:7: TypeError: Write of private field #x to an object which did not contain the field *%(basename)s:7: TypeError: Cannot write private member #x to an object whose class did not declare it
setX(o, val) { o.#x = val; } setX(o, val) { o.#x = val; }
^ ^
TypeError: Write of private field #x to an object which did not contain the field TypeError: Cannot write private member #x to an object whose class did not declare it
at X.setX (*%(basename)s:7:23) at X.setX (*%(basename)s:7:23)
at *%(basename)s:10:9 at *%(basename)s:10:9
\ No newline at end of file
...@@ -8,12 +8,40 @@ ...@@ -8,12 +8,40 @@
// Complementary private accessors. // Complementary private accessors.
{ {
let store = 1;
class C { class C {
get #a() { } get #a() { return store; }
set #a(val) { } set #a(val) { store = val; }
incA() { this.#a++; } // CountOperation
setA(val) { this.#a = val; }
getA() { return this.#a; }
} }
new C; const c = new C;
assertEquals(store, c.getA());
assertEquals(1, c.getA());
c.setA(2);
assertEquals(store, c.getA());
assertEquals(2, c.getA());
c.incA();
assertEquals(store, c.getA());
assertEquals(3, c.getA());
}
// Compound assignment.
{
let store;
class A {
get #a() { return store; }
set #a(val) { store = val; }
getA() { return this.#a; }
constructor(val) {
({ y: this.#a } = val);
}
}
const a = new A({y: 'test'});
assertEquals('test', a.getA());
} }
// Accessing super in private accessors. // Accessing super in private accessors.
...@@ -39,13 +67,20 @@ ...@@ -39,13 +67,20 @@
// Nested private accessors. // Nested private accessors.
{ {
class C { class C {
a() { this.#a; }
get #a() { get #a() {
class D { get #a() { } } let storeD = 'd';
class D {
// Shadows outer #a
get #a() { return storeD; }
getD() { return this.#a; }
}
return new D; return new D;
} }
getA() {
return this.#a;
}
} }
new C().a(); assertEquals('d', new C().getA().getD());
} }
// Duplicate private accessors. // Duplicate private accessors.
......
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