mirror of
https://github.com/tc39/test262.git
synced 2025-09-23 10:08:49 +02:00
[nonextensible-applies-to-private] Adding private field to non-extensible object throws (#4577)
* [nonextensible-applies-to-private] Adding private field to non-extensible object throws * add feature nonextensible-applies-to-private * extending tests in response to reviewer suggestions * use const instead of let
This commit is contained in:
parent
e0d8f66a2b
commit
822589b1ef
@ -88,6 +88,10 @@ upsert
|
||||
# https://github.com/tc39/proposal-immutable-arraybuffer
|
||||
immutable-arraybuffer
|
||||
|
||||
# Non-extensible Applies to Private
|
||||
# https://github.com/tc39/proposal-nonextensible-applies-to-private
|
||||
nonextensible-applies-to-private
|
||||
|
||||
## Standard language features
|
||||
#
|
||||
# Language features that have been included in a published version of the
|
||||
|
@ -1,31 +0,0 @@
|
||||
// Copyright (C) 2019 Caio Lima. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
description: It is possible to add private fields on frozen objects
|
||||
esid: sec-define-field
|
||||
info: |
|
||||
DefineField(receiver, fieldRecord)
|
||||
...
|
||||
8. If fieldName is a Private Name,
|
||||
a. Perform ? PrivateFieldAdd(fieldName, receiver, initValue).
|
||||
9. Else,
|
||||
a. Assert: IsPropertyKey(fieldName) is true.
|
||||
b. Perform ? CreateDataPropertyOrThrow(receiver, fieldName, initValue).
|
||||
10. Return.
|
||||
features: [class, class-fields-private, class-fields-public]
|
||||
flags: [onlyStrict]
|
||||
---*/
|
||||
|
||||
class Test {
|
||||
f = this;
|
||||
#g = (Object.freeze(this), "Test262");
|
||||
|
||||
get g() {
|
||||
return this.#g;
|
||||
}
|
||||
}
|
||||
|
||||
let t = new Test();
|
||||
assert.sameValue(t.f, t);
|
||||
assert.sameValue(t.g, "Test262");
|
@ -0,0 +1,117 @@
|
||||
// Copyright (C) 2019 Caio Lima. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
description: It is not possible to add private fields on non-extensible objects
|
||||
esid: sec-define-field
|
||||
info: |
|
||||
1.1 PrivateFieldAdd ( O, P, value )
|
||||
1. If O.[[Extensible]] is false, throw a TypeError exception.
|
||||
...
|
||||
|
||||
features:
|
||||
- class
|
||||
- class-fields-private
|
||||
- class-fields-public
|
||||
- nonextensible-applies-to-private
|
||||
flags: [onlyStrict]
|
||||
---*/
|
||||
|
||||
// Analogous to
|
||||
// test/language/statements/class/subclass/private-class-field-on-nonextensible-return-override.js
|
||||
|
||||
class NonExtensibleBase {
|
||||
constructor(seal) {
|
||||
if (seal) Object.preventExtensions(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// extend superclass with private instance data field
|
||||
class ClassWithPrivateField extends NonExtensibleBase {
|
||||
#val;
|
||||
|
||||
constructor(seal) {
|
||||
super(seal);
|
||||
this.#val = 42;
|
||||
}
|
||||
val() {
|
||||
return this.#val;
|
||||
}
|
||||
}
|
||||
|
||||
const t = new ClassWithPrivateField(false);
|
||||
// extensible objects can be extended
|
||||
assert.sameValue(t.val(), 42);
|
||||
|
||||
// where superclass prevented extensions & subclass extended
|
||||
assert.throws(TypeError, function () {
|
||||
new ClassWithPrivateField(true);
|
||||
});
|
||||
|
||||
|
||||
// extend superclass with private instance method
|
||||
class ClassWithPrivateMethod extends NonExtensibleBase {
|
||||
constructor(seal) {
|
||||
super(seal);
|
||||
}
|
||||
// private methods are on the instance, so will fail
|
||||
#privateMethod() {
|
||||
return 42;
|
||||
};
|
||||
// public methods are on the prototype, so are ok.
|
||||
publicMethod() {
|
||||
return this.#privateMethod();
|
||||
}
|
||||
}
|
||||
|
||||
const m = new ClassWithPrivateMethod(false);
|
||||
// extensible objects can be extended
|
||||
assert.sameValue(m.publicMethod(), 42);
|
||||
|
||||
// where superclass prevented extensions & subclass extended
|
||||
assert.throws(TypeError, function () {
|
||||
new ClassWithPrivateMethod(true);
|
||||
});
|
||||
|
||||
|
||||
// extend superclass with private instance accessor
|
||||
class ClassWithPrivateAccessor extends NonExtensibleBase {
|
||||
constructor(seal) {
|
||||
super(seal);
|
||||
}
|
||||
// private accessors are on the instance, so will fail
|
||||
get #privateAccessor() {
|
||||
return 42;
|
||||
};
|
||||
// public accessors are on the prototype, so are ok.
|
||||
get publicAccessor() {
|
||||
return this.#privateAccessor;
|
||||
}
|
||||
}
|
||||
|
||||
const a = new ClassWithPrivateAccessor(false);
|
||||
// extensible objects can be extended
|
||||
assert.sameValue(m.publicAccessor, 42);
|
||||
|
||||
// where superclass prevented extensions & subclass extended
|
||||
assert.throws(TypeError, function () {
|
||||
new ClassWithPrivateAccessor(true);
|
||||
});
|
||||
|
||||
|
||||
// base class private instance data field
|
||||
class TestNonExtensibleData {
|
||||
#g = (Object.preventExtensions(this), "Test262");
|
||||
}
|
||||
|
||||
assert.throws(TypeError, function () {
|
||||
new TestNonExtensibleData();
|
||||
});
|
||||
|
||||
// base class with private static data field
|
||||
assert.throws(TypeError, function () {
|
||||
class TestNonExtensibleStaticData {
|
||||
static #g = (Object.preventExtensions(TestNonExtensibleStaticData), "Test262");
|
||||
}
|
||||
});
|
@ -0,0 +1,100 @@
|
||||
// Copyright (C) 2019 Caio Lima. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
description: It is not possible to add private fields on non-extensible objects via return override
|
||||
esid: sec-define-field
|
||||
info: |
|
||||
1.1 PrivateFieldAdd ( O, P, value )
|
||||
1. If O.[[Extensible]] is false, throw a TypeError exception.
|
||||
...
|
||||
|
||||
features:
|
||||
- class
|
||||
- class-fields-private
|
||||
- class-fields-public
|
||||
- nonextensible-applies-to-private
|
||||
flags: [onlyStrict]
|
||||
---*/
|
||||
|
||||
// Analogous to
|
||||
// test/language/statements/class/elements/private-class-field-on-nonextensible-objects.js
|
||||
|
||||
class TrojanBase {
|
||||
constructor(obj) {
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// extend superclass with private instance data field
|
||||
class ClassWithPrivateField extends TrojanBase {
|
||||
#val;
|
||||
|
||||
constructor(obj) {
|
||||
super(obj);
|
||||
this.#val = 42;
|
||||
}
|
||||
val() {
|
||||
return this.#val;
|
||||
}
|
||||
}
|
||||
|
||||
const t = new ClassWithPrivateField({});
|
||||
// extensible objects can be extended
|
||||
assert.sameValue(t.val(), 42);
|
||||
|
||||
// where superclass prevented extensions & subclass extended
|
||||
assert.throws(TypeError, function () {
|
||||
new ClassWithPrivateField(Object.preventExtensions({}));
|
||||
});
|
||||
|
||||
|
||||
// extend superclass with private instance method
|
||||
class ClassWithPrivateMethod extends TrojanBase {
|
||||
constructor(obj) {
|
||||
super(obj);
|
||||
}
|
||||
// private methods are on the instance, so will fail
|
||||
#privateMethod() {
|
||||
return 42;
|
||||
};
|
||||
// public methods are on the prototype, so are ok.
|
||||
publicMethod() {
|
||||
return this.#privateMethod();
|
||||
}
|
||||
}
|
||||
|
||||
const m = new ClassWithPrivateMethod({});
|
||||
// extensible objects can be extended
|
||||
assert.sameValue(m.publicMethod(), 42);
|
||||
|
||||
// where superclass prevented extensions & subclass extended
|
||||
assert.throws(TypeError, function () {
|
||||
new ClassWithPrivateMethod(Object.preventExtensions({}));
|
||||
});
|
||||
|
||||
|
||||
// extend superclass with private instance accessor
|
||||
class ClassWithPrivateAccessor extends TrojanBase {
|
||||
constructor(obj) {
|
||||
super(obj);
|
||||
}
|
||||
// private accessors are on the instance, so will fail
|
||||
get #privateAccessor() {
|
||||
return 42;
|
||||
};
|
||||
// public accessors are on the prototype, so are ok.
|
||||
get publicAccessor() {
|
||||
return this.#privateAccessor;
|
||||
}
|
||||
}
|
||||
|
||||
const a = new ClassWithPrivateAccessor({});
|
||||
// extensible objects can be extended
|
||||
assert.sameValue(m.publicAccessor, 42);
|
||||
|
||||
// where superclass prevented extensions & subclass extended
|
||||
assert.throws(TypeError, function () {
|
||||
new ClassWithPrivateAccessor(Object.preventExtensions({}));
|
||||
});
|
@ -2,6 +2,11 @@
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
features:
|
||||
- class
|
||||
- class-fields-private
|
||||
- class-fields-public
|
||||
- nonextensible-applies-to-private
|
||||
flags:
|
||||
- noStrict
|
||||
description: |
|
||||
@ -32,8 +37,8 @@ class A extends OverrideBase {
|
||||
}
|
||||
|
||||
var obj = {};
|
||||
Object.seal(obj);
|
||||
new A(obj); // Add #a to obj, but not g.
|
||||
Object.seal(obj);
|
||||
assert.sameValue('g' in obj, false);
|
||||
assert.sameValue(A.gs(obj), 1);
|
||||
A.inca(obj);
|
||||
@ -67,8 +72,10 @@ assert.sameValue(A.gs(proxy), 2)
|
||||
|
||||
var target = { a: 10 };
|
||||
Object.freeze(target);
|
||||
new A(target);
|
||||
assert.sameValue(Object.isFrozen(target), true)
|
||||
assert.throws(TypeError, function () {
|
||||
new A(target);
|
||||
});
|
||||
assert.sameValue(Object.isFrozen(target), true);
|
||||
|
||||
var getOwnKeys = [];
|
||||
var proxy = new Proxy(target, {
|
||||
@ -80,4 +87,3 @@ var proxy = new Proxy(target, {
|
||||
|
||||
Object.isFrozen(proxy);
|
||||
assert.sameValue(getOwnKeys.length, 1);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user