mirror of
https://github.com/tc39/test262.git
synced 2025-09-24 10:38:30 +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
|
# https://github.com/tc39/proposal-immutable-arraybuffer
|
||||||
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
|
## Standard language features
|
||||||
#
|
#
|
||||||
# Language features that have been included in a published version of the
|
# 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.
|
// 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:
|
flags:
|
||||||
- noStrict
|
- noStrict
|
||||||
description: |
|
description: |
|
||||||
@ -32,8 +37,8 @@ class A extends OverrideBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var obj = {};
|
var obj = {};
|
||||||
Object.seal(obj);
|
|
||||||
new A(obj); // Add #a to obj, but not g.
|
new A(obj); // Add #a to obj, but not g.
|
||||||
|
Object.seal(obj);
|
||||||
assert.sameValue('g' in obj, false);
|
assert.sameValue('g' in obj, false);
|
||||||
assert.sameValue(A.gs(obj), 1);
|
assert.sameValue(A.gs(obj), 1);
|
||||||
A.inca(obj);
|
A.inca(obj);
|
||||||
@ -67,8 +72,10 @@ assert.sameValue(A.gs(proxy), 2)
|
|||||||
|
|
||||||
var target = { a: 10 };
|
var target = { a: 10 };
|
||||||
Object.freeze(target);
|
Object.freeze(target);
|
||||||
new A(target);
|
assert.throws(TypeError, function () {
|
||||||
assert.sameValue(Object.isFrozen(target), true)
|
new A(target);
|
||||||
|
});
|
||||||
|
assert.sameValue(Object.isFrozen(target), true);
|
||||||
|
|
||||||
var getOwnKeys = [];
|
var getOwnKeys = [];
|
||||||
var proxy = new Proxy(target, {
|
var proxy = new Proxy(target, {
|
||||||
@ -80,4 +87,3 @@ var proxy = new Proxy(target, {
|
|||||||
|
|
||||||
Object.isFrozen(proxy);
|
Object.isFrozen(proxy);
|
||||||
assert.sameValue(getOwnKeys.length, 1);
|
assert.sameValue(getOwnKeys.length, 1);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user