From bef77dc1448202dd47e53c2d614faac2e3ce1766 Mon Sep 17 00:00:00 2001 From: Valerie R Young Date: Wed, 1 Nov 2017 21:59:11 -0400 Subject: [PATCH] classfields: PrivateFieldSet and PrivateFieldGet --- .../class/privatefieldget-success-1.js | 46 +++++++++++++++ .../class/privatefieldget-success-2.js | 44 ++++++++++++++ .../class/privatefieldget-success-3.js | 41 +++++++++++++ .../class/privatefieldget-success-4.js | 40 +++++++++++++ .../class/privatefieldget-success-5.js | 40 +++++++++++++ .../class/privatefieldget-typeerror-1.js | 39 ++++++++++++ .../class/privatefieldget-typeerror-2.js | 55 +++++++++++++++++ .../class/privatefieldget-typeerror-3.js | 55 +++++++++++++++++ .../class/privatefieldget-typeerror-4.js | 53 +++++++++++++++++ .../class/privatefieldget-typeerror-5.js | 58 ++++++++++++++++++ .../class/privatefieldset-typeerror-1.js | 39 ++++++++++++ .../class/privatefieldset-typeerror-2.js | 55 +++++++++++++++++ .../class/privatefieldset-typeerror-3.js | 55 +++++++++++++++++ .../class/privatefieldset-typeerror-4.js | 53 +++++++++++++++++ .../class/privatefieldset-typeerror-5.js | 59 +++++++++++++++++++ 15 files changed, 732 insertions(+) create mode 100644 test/language/statements/class/privatefieldget-success-1.js create mode 100644 test/language/statements/class/privatefieldget-success-2.js create mode 100644 test/language/statements/class/privatefieldget-success-3.js create mode 100644 test/language/statements/class/privatefieldget-success-4.js create mode 100644 test/language/statements/class/privatefieldget-success-5.js create mode 100644 test/language/statements/class/privatefieldget-typeerror-1.js create mode 100644 test/language/statements/class/privatefieldget-typeerror-2.js create mode 100644 test/language/statements/class/privatefieldget-typeerror-3.js create mode 100644 test/language/statements/class/privatefieldget-typeerror-4.js create mode 100644 test/language/statements/class/privatefieldget-typeerror-5.js create mode 100644 test/language/statements/class/privatefieldset-typeerror-1.js create mode 100644 test/language/statements/class/privatefieldset-typeerror-2.js create mode 100644 test/language/statements/class/privatefieldset-typeerror-3.js create mode 100644 test/language/statements/class/privatefieldset-typeerror-4.js create mode 100644 test/language/statements/class/privatefieldset-typeerror-5.js diff --git a/test/language/statements/class/privatefieldget-success-1.js b/test/language/statements/class/privatefieldget-success-1.js new file mode 100644 index 0000000000..73836bd040 --- /dev/null +++ b/test/language/statements/class/privatefieldget-success-1.js @@ -0,0 +1,46 @@ +// Copyright (C) 2017 Valerie Young. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: Successfully access private field +esid: sec-getvalue +info: | + GetValue ( V ) + ... + 5. If IsPropertyReference(V), then + ... + b. If IsPrivateReference(V), then + i. Let env be the running execution context's PrivateNameEnvironment. + ii. Let field be ? ResolveBinding(GetReferencedName(V), env). + iii. Assert: field is a Private Name. + iv. Return ? PrivateFieldGet(field, base). + + PrivateFieldGet (P, O ) + 1. Assert: P is a Private Name value. + 2. If O is not an object, throw a TypeError exception. + 3. Let entry be PrivateFieldFind(P, O). + 4. If entry is empty, throw a TypeError exception. + 5. Return entry.[[PrivateFieldValue]]. + +features: [class-fields] +---*/ + +class Outer { + #x = 42; + + innerclass() { + var self = this; + + return class extends Outer { + f() { + return self.#x; + } + } + } +} + +var Inner = new Outer().innerclass(); +var i = new Inner(); +var value = i.f(); + +assert.sameValue(value, 42) diff --git a/test/language/statements/class/privatefieldget-success-2.js b/test/language/statements/class/privatefieldget-success-2.js new file mode 100644 index 0000000000..adc4e9a10f --- /dev/null +++ b/test/language/statements/class/privatefieldget-success-2.js @@ -0,0 +1,44 @@ +// Copyright (C) 2017 Valerie Young. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: Successfully access private field +esid: sec-getvalue +info: | + GetValue ( V ) + ... + 5. If IsPropertyReference(V), then + ... + b. If IsPrivateReference(V), then + i. Let env be the running execution context's PrivateNameEnvironment. + ii. Let field be ? ResolveBinding(GetReferencedName(V), env). + iii. Assert: field is a Private Name. + iv. Return ? PrivateFieldGet(field, base). + + PrivateFieldGet (P, O ) + 1. Assert: P is a Private Name value. + 2. If O is not an object, throw a TypeError exception. + 3. Let entry be PrivateFieldFind(P, O). + 4. If entry is empty, throw a TypeError exception. + 5. Return entry.[[PrivateFieldValue]]. + +features: [class-fields] +---*/ + + +class A { + #x = 'Avalue'; + x() { + return this.#x; + } +} +class B extends A { + #x = 'Bvalue'; + x() { + return this.#x; + } +} + +var b = new B(); + +assert.sameValue(b.x(), 'Bvalue') diff --git a/test/language/statements/class/privatefieldget-success-3.js b/test/language/statements/class/privatefieldget-success-3.js new file mode 100644 index 0000000000..d9722f5639 --- /dev/null +++ b/test/language/statements/class/privatefieldget-success-3.js @@ -0,0 +1,41 @@ +// Copyright (C) 2017 Valerie Young. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: Successfully access private field +esid: sec-getvalue +info: | + GetValue ( V ) + ... + 5. If IsPropertyReference(V), then + ... + b. If IsPrivateReference(V), then + i. Let env be the running execution context's PrivateNameEnvironment. + ii. Let field be ? ResolveBinding(GetReferencedName(V), env). + iii. Assert: field is a Private Name. + iv. Return ? PrivateFieldGet(field, base). + + PrivateFieldGet (P, O ) + 1. Assert: P is a Private Name value. + 2. If O is not an object, throw a TypeError exception. + 3. Let entry be PrivateFieldFind(P, O). + 4. If entry is empty, throw a TypeError exception. + 5. Return entry.[[PrivateFieldValue]]. + +features: [class-fields] +---*/ + + +class A { + #x = 'Avalue'; + x() { + return this.#x; + } +} +class B extends A { + #x = 'Bvalue'; +} + +var b = new B(); + +assert.sameValue(b.x(), 'Avalue') diff --git a/test/language/statements/class/privatefieldget-success-4.js b/test/language/statements/class/privatefieldget-success-4.js new file mode 100644 index 0000000000..7253d32f1c --- /dev/null +++ b/test/language/statements/class/privatefieldget-success-4.js @@ -0,0 +1,40 @@ +// Copyright (C) 2017 Valerie Young. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: Successfully access private field +esid: sec-getvalue +info: | + GetValue ( V ) + ... + 5. If IsPropertyReference(V), then + ... + b. If IsPrivateReference(V), then + i. Let env be the running execution context's PrivateNameEnvironment. + ii. Let field be ? ResolveBinding(GetReferencedName(V), env). + iii. Assert: field is a Private Name. + iv. Return ? PrivateFieldGet(field, base). + + PrivateFieldGet (P, O ) + 1. Assert: P is a Private Name value. + 2. If O is not an object, throw a TypeError exception. + 3. Let entry be PrivateFieldFind(P, O). + 4. If entry is empty, throw a TypeError exception. + 5. Return entry.[[PrivateFieldValue]]. + +features: [class-fields] +---*/ + + +class A { + #x = 'Avalue'; + x() { + return this.#x; + } +} +class B extends A { +} + +var b = new B(); + +assert.sameValue(b.x(), 'Avalue') diff --git a/test/language/statements/class/privatefieldget-success-5.js b/test/language/statements/class/privatefieldget-success-5.js new file mode 100644 index 0000000000..9bf09e9ea4 --- /dev/null +++ b/test/language/statements/class/privatefieldget-success-5.js @@ -0,0 +1,40 @@ +// Copyright (C) 2017 Valerie Young. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: Successfully access private field +esid: sec-getvalue +info: | + GetValue ( V ) + ... + 5. If IsPropertyReference(V), then + ... + b. If IsPrivateReference(V), then + i. Let env be the running execution context's PrivateNameEnvironment. + ii. Let field be ? ResolveBinding(GetReferencedName(V), env). + iii. Assert: field is a Private Name. + iv. Return ? PrivateFieldGet(field, base). + + PrivateFieldGet (P, O ) + 1. Assert: P is a Private Name value. + 2. If O is not an object, throw a TypeError exception. + 3. Let entry be PrivateFieldFind(P, O). + 4. If entry is empty, throw a TypeError exception. + 5. Return entry.[[PrivateFieldValue]]. + +features: [class-fields] +---*/ + + +class C { + #x = 42; + f() { + return this.#x; + } +} + +var c1 = new C(); +var c2 = new C(); +var value = c2.f.call(c1); + +assert.sameValue(value, 'Avalue'); diff --git a/test/language/statements/class/privatefieldget-typeerror-1.js b/test/language/statements/class/privatefieldget-typeerror-1.js new file mode 100644 index 0000000000..1f1f201449 --- /dev/null +++ b/test/language/statements/class/privatefieldget-typeerror-1.js @@ -0,0 +1,39 @@ +// Copyright (C) 2017 Valerie Young. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: Cannot access private field before the entry was added to [[PrivateFieldValues]] +esid: sec-getvalue +info: | + GetValue ( V ) + ... + 5. If IsPropertyReference(V), then + ... + b. If IsPrivateReference(V), then + i. Let env be the running execution context's PrivateNameEnvironment. + ii. Let field be ? ResolveBinding(GetReferencedName(V), env). + iii. Assert: field is a Private Name. + iv. Return ? PrivateFieldGet(field, base). + + PrivateFieldGet (P, O ) + 1. Assert: P is a Private Name value. + 2. If O is not an object, throw a TypeError exception. + 3. Let entry be PrivateFieldFind(P, O). + 4. If entry is empty, throw a TypeError exception. + + PrivateFieldFind (P, O) + 1. Assert: P is a Private Name value. + 2. Assert: O is an object with a [[PrivateFieldValues]] internal slot. + 3. For each element entry in O.[[PrivateFieldValues]], + a. If entry.[[PrivateName]] is P, return entry. + 4. Return empty. + +features: [class-fields] +---*/ + +class C { + y = this.#x; + #x; +} + +assert.throws(TypeError, function() { new C(); }) diff --git a/test/language/statements/class/privatefieldget-typeerror-2.js b/test/language/statements/class/privatefieldget-typeerror-2.js new file mode 100644 index 0000000000..4a5f6be656 --- /dev/null +++ b/test/language/statements/class/privatefieldget-typeerror-2.js @@ -0,0 +1,55 @@ +// Copyright (C) 2017 Valerie Young. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: TypeError when referenced private field cannot be found in `this`'s [[PrivateFieldValues]] +esid: sec-getvalue +info: | + GetValue ( V ) + ... + 5. If IsPropertyReference(V), then + ... + b. If IsPrivateReference(V), then + i. Let env be the running execution context's PrivateNameEnvironment. + ii. Let field be ? ResolveBinding(GetReferencedName(V), env). + iii. Assert: field is a Private Name. + iv. Return ? PrivateFieldGet(field, base). + + PrivateFieldGet (P, O ) + 1. Assert: P is a Private Name value. + 2. If O is not an object, throw a TypeError exception. + 3. Let entry be PrivateFieldFind(P, O). + 4. If entry is empty, throw a TypeError exception. + + PrivateFieldFind (P, O) + 1. Assert: P is a Private Name value. + 2. Assert: O is an object with a [[PrivateFieldValues]] internal slot. + 3. For each element entry in O.[[PrivateFieldValues]], + a. If entry.[[PrivateName]] is P, return entry. + 4. Return empty. + +features: [class-fields] +---*/ + +class Outer { + #x = 42; + + innerclass() { + + // create class within in Outerclass -- the PrivateNameEnvironment binding for + // private field `#x` is resolvable. + return class { + f() { + return this.#x; + } + } + } +} + +var Inner = new Outer().innerclass(); +var i = new Inner(); + +assert.throws(TypeError, function() { + // when f() is called, the private field will not be found in Inner's `this` + i.f(); +}) diff --git a/test/language/statements/class/privatefieldget-typeerror-3.js b/test/language/statements/class/privatefieldget-typeerror-3.js new file mode 100644 index 0000000000..8c1ef2748b --- /dev/null +++ b/test/language/statements/class/privatefieldget-typeerror-3.js @@ -0,0 +1,55 @@ +// Copyright (C) 2017 Valerie Young. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: TypeError when referenced private field cannot be found in `this`'s [[PrivateFieldValues]] +esid: sec-getvalue +info: | + GetValue ( V ) + ... + 5. If IsPropertyReference(V), then + ... + b. If IsPrivateReference(V), then + i. Let env be the running execution context's PrivateNameEnvironment. + ii. Let field be ? ResolveBinding(GetReferencedName(V), env). + iii. Assert: field is a Private Name. + iv. Return ? PrivateFieldGet(field, base). + + PrivateFieldGet (P, O ) + 1. Assert: P is a Private Name value. + 2. If O is not an object, throw a TypeError exception. + 3. Let entry be PrivateFieldFind(P, O). + 4. If entry is empty, throw a TypeError exception. + + PrivateFieldFind (P, O) + 1. Assert: P is a Private Name value. + 2. Assert: O is an object with a [[PrivateFieldValues]] internal slot. + 3. For each element entry in O.[[PrivateFieldValues]], + a. If entry.[[PrivateName]] is P, return entry. + 4. Return empty. + +features: [class-fields] +---*/ + +class Outer { + #x = 42; + + innerclass() { + + // create class within in Outerclass -- the PrivateNameEnvironment binding for + // private field `#x` is resolvable. + return class extends Outer { + f() { + return this.#x; + } + } + } +} + +var Inner = new Outer().innerclass(); +var i = new Inner(); + +assert.throws(TypeError, function() { + // when f() is called, the private field will not be found in Inner's `this` + i.f(); +}) diff --git a/test/language/statements/class/privatefieldget-typeerror-4.js b/test/language/statements/class/privatefieldget-typeerror-4.js new file mode 100644 index 0000000000..61f2d3a78d --- /dev/null +++ b/test/language/statements/class/privatefieldget-typeerror-4.js @@ -0,0 +1,53 @@ +// Copyright (C) 2017 Valerie Young. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: TypeError when referenced private field cannot be found in `this`'s [[PrivateFieldValues]] +esid: sec-getvalue +info: | + GetValue ( V ) + ... + 5. If IsPropertyReference(V), then + ... + b. If IsPrivateReference(V), then + i. Let env be the running execution context's PrivateNameEnvironment. + ii. Let field be ? ResolveBinding(GetReferencedName(V), env). + iii. Assert: field is a Private Name. + iv. Return ? PrivateFieldGet(field, base). + + PrivateFieldGet (P, O ) + 1. Assert: P is a Private Name value. + 2. If O is not an object, throw a TypeError exception. + 3. Let entry be PrivateFieldFind(P, O). + 4. If entry is empty, throw a TypeError exception. + + PrivateFieldFind (P, O) + 1. Assert: P is a Private Name value. + 2. Assert: O is an object with a [[PrivateFieldValues]] internal slot. + 3. For each element entry in O.[[PrivateFieldValues]], + a. If entry.[[PrivateName]] is P, return entry. + 4. Return empty. + +features: [class-fields] +---*/ + +function classfactory() { + return class { + #x; + f() { + this.#x; + } + } +} + +var C1 = classfactory(); +var C2 = classfactory(); + +c1 = new C1(); +c2 = new C2(); + +assert.throws(TypeError, function() { + // when f() is called in class C1, the Private Name binding for #x in C1 will + // not found in C2's [[PrivateNameValues]] + c1.f.call(c2); +}) diff --git a/test/language/statements/class/privatefieldget-typeerror-5.js b/test/language/statements/class/privatefieldget-typeerror-5.js new file mode 100644 index 0000000000..ff1f3737c1 --- /dev/null +++ b/test/language/statements/class/privatefieldget-typeerror-5.js @@ -0,0 +1,58 @@ +// Copyright (C) 2017 Valerie Young. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: TypeError when referenced private field cannot be found in `this`'s [[PrivateFieldValues]] +esid: sec-getvalue +info: | + GetValue ( V ) + ... + 5. If IsPropertyReference(V), then + ... + b. If IsPrivateReference(V), then + i. Let env be the running execution context's PrivateNameEnvironment. + ii. Let field be ? ResolveBinding(GetReferencedName(V), env). + iii. Assert: field is a Private Name. + iv. Return ? PrivateFieldGet(field, base). + + PrivateFieldGet (P, O ) + 1. Assert: P is a Private Name value. + 2. If O is not an object, throw a TypeError exception. + 3. Let entry be PrivateFieldFind(P, O). + 4. If entry is empty, throw a TypeError exception. + + PrivateFieldFind (P, O) + 1. Assert: P is a Private Name value. + 2. Assert: O is an object with a [[PrivateFieldValues]] internal slot. + 3. For each element entry in O.[[PrivateFieldValues]], + a. If entry.[[PrivateName]] is P, return entry. + 4. Return empty. + +features: [class-fields] +---*/ + +class Outer { + #x = 42; + + innerclass() { + var self = this; + + return class extends Outer { + #x = 'not42'; + f() { + return self.#x; + } + } + } +} + +var Inner = new Outer().innerclass(); +var i = new Inner(); + +assert.throws(TypeError, function() { + // when f() is called, the entry in the PrivateNameEnironment's environment + // record for '#x' will contain the Inner class's Private Name for '#x'. + // When this Private Name is used for lookup on the `self` object, it + // will not be found (as the `self` object has the Outer's Private Name for #x) + i.f(); +}) diff --git a/test/language/statements/class/privatefieldset-typeerror-1.js b/test/language/statements/class/privatefieldset-typeerror-1.js new file mode 100644 index 0000000000..ddd1a3f199 --- /dev/null +++ b/test/language/statements/class/privatefieldset-typeerror-1.js @@ -0,0 +1,39 @@ +// Copyright (C) 2017 Valerie Young. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: TypeError when setting private field before the entry was added to [[PrivateFieldValues]] +esid: sec-putvalue +info: | + PutValue ( V, W ) + ... + 5. Else if IsPropertyReference(V), then + ... + b. If IsPrivateReference(V), then + i. Let env be the running execution context's PrivateNameEnvironment. + ii. Let field be ? ResolveBinding(GetReferencedName(V), env). + iii. Assert: field is a Private Name. + iv. Perform ? PrivateFieldSet(field, base, W). + + PrivateFieldSet (P, O, value ) + 1. Assert: P is a Private Name value. + 2. If O is not an object, throw a TypeError exception. + 3. Let entry be PrivateFieldFind(P, O). + 4. If entry is empty, throw a TypeError exception. + + PrivateFieldFind (P, O) + 1. Assert: P is a Private Name value. + 2. Assert: O is an object with a [[PrivateFieldValues]] internal slot. + 3. For each element entry in O.[[PrivateFieldValues]], + a. If entry.[[PrivateName]] is P, return entry. + 4. Return empty. + +features: [class-fields] +---*/ + +class C { + y = this.#x = 1; + #x; +} + +assert.throws(TypeError, function() { new C(); }) diff --git a/test/language/statements/class/privatefieldset-typeerror-2.js b/test/language/statements/class/privatefieldset-typeerror-2.js new file mode 100644 index 0000000000..8f83e513ea --- /dev/null +++ b/test/language/statements/class/privatefieldset-typeerror-2.js @@ -0,0 +1,55 @@ +// Copyright (C) 2017 Valerie Young. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: TypeError when setting private field not in `this`'s [[PrivateFieldValues]] +esid: sec-putvalue +info: | + PutValue ( V, W ) + ... + 5. Else if IsPropertyReference(V), then + ... + b. If IsPrivateReference(V), then + i. Let env be the running execution context's PrivateNameEnvironment. + ii. Let field be ? ResolveBinding(GetReferencedName(V), env). + iii. Assert: field is a Private Name. + iv. Perform ? PrivateFieldSet(field, base, W). + + PrivateFieldSet (P, O, value ) + 1. Assert: P is a Private Name value. + 2. If O is not an object, throw a TypeError exception. + 3. Let entry be PrivateFieldFind(P, O). + 4. If entry is empty, throw a TypeError exception. + + PrivateFieldFind (P, O) + 1. Assert: P is a Private Name value. + 2. Assert: O is an object with a [[PrivateFieldValues]] internal slot. + 3. For each element entry in O.[[PrivateFieldValues]], + a. If entry.[[PrivateName]] is P, return entry. + 4. Return empty. + +features: [class-fields] +---*/ + +class Outer { + #x = 42; + + innerclass() { + + // create class within in Outerclass -- the PrivateNameEnvironment binding for + // private field `#x` is resolvable. + return class { + f() { + this.#x = 1; + } + } + } +} + +var Inner = new Outer().innerclass(); +var i = new Inner(); + +assert.throws(TypeError, function() { + // when f() is called, the private field will not be found in Inner's `this` + i.f(); +}) diff --git a/test/language/statements/class/privatefieldset-typeerror-3.js b/test/language/statements/class/privatefieldset-typeerror-3.js new file mode 100644 index 0000000000..4a0bfabd90 --- /dev/null +++ b/test/language/statements/class/privatefieldset-typeerror-3.js @@ -0,0 +1,55 @@ +// Copyright (C) 2017 Valerie Young. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: TypeError when setting private field not in `this`'s [[PrivateFieldValues]] +esid: sec-putvalue +info: | + PutValue ( V, W ) + ... + 5. Else if IsPropertyReference(V), then + ... + b. If IsPrivateReference(V), then + i. Let env be the running execution context's PrivateNameEnvironment. + ii. Let field be ? ResolveBinding(GetReferencedName(V), env). + iii. Assert: field is a Private Name. + iv. Perform ? PrivateFieldSet(field, base, W). + + PrivateFieldSet (P, O, value ) + 1. Assert: P is a Private Name value. + 2. If O is not an object, throw a TypeError exception. + 3. Let entry be PrivateFieldFind(P, O). + 4. If entry is empty, throw a TypeError exception. + + PrivateFieldFind (P, O) + 1. Assert: P is a Private Name value. + 2. Assert: O is an object with a [[PrivateFieldValues]] internal slot. + 3. For each element entry in O.[[PrivateFieldValues]], + a. If entry.[[PrivateName]] is P, return entry. + 4. Return empty. + +features: [class-fields] +---*/ + +class Outer { + #x = 42; + + innerclass() { + + // create class within in Outerclass -- the PrivateNameEnvironment binding for + // private field `#x` is resolvable. + return class extends Outer { + f() { + this.#x = 1; + } + } + } +} + +var Inner = new Outer().innerclass(); +var i = new Inner(); + +assert.throws(TypeError, function() { + // when f() is called, the private field will not be found in Inner's `this` + i.f(); +}) diff --git a/test/language/statements/class/privatefieldset-typeerror-4.js b/test/language/statements/class/privatefieldset-typeerror-4.js new file mode 100644 index 0000000000..d3dc0ab966 --- /dev/null +++ b/test/language/statements/class/privatefieldset-typeerror-4.js @@ -0,0 +1,53 @@ +// Copyright (C) 2017 Valerie Young. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: TypeError when setting private field not in `this`'s [[PrivateFieldValues]] +esid: sec-putvalue +info: | + PutValue ( V, W ) + ... + 5. Else if IsPropertyReference(V), then + ... + b. If IsPrivateReference(V), then + i. Let env be the running execution context's PrivateNameEnvironment. + ii. Let field be ? ResolveBinding(GetReferencedName(V), env). + iii. Assert: field is a Private Name. + iv. Perform ? PrivateFieldSet(field, base, W). + + PrivateFieldSet (P, O, value ) + 1. Assert: P is a Private Name value. + 2. If O is not an object, throw a TypeError exception. + 3. Let entry be PrivateFieldFind(P, O). + 4. If entry is empty, throw a TypeError exception. + + PrivateFieldFind (P, O) + 1. Assert: P is a Private Name value. + 2. Assert: O is an object with a [[PrivateFieldValues]] internal slot. + 3. For each element entry in O.[[PrivateFieldValues]], + a. If entry.[[PrivateName]] is P, return entry. + 4. Return empty. + +features: [class-fields] +---*/ + +function classfactory() { + return class { + #x; + f() { + this.#x = 1; + } + } +} + +var C1 = classfactory(); +var C2 = classfactory(); + +c1 = new C1(); +c2 = new C2(); + +assert.throws(TypeError, function() { + // when f() is called in class C1, the Private Name binding for #x in C1 will + // not found in C2's [[PrivateNameValues]] + c1.f.call(c2); +}) diff --git a/test/language/statements/class/privatefieldset-typeerror-5.js b/test/language/statements/class/privatefieldset-typeerror-5.js new file mode 100644 index 0000000000..7ccdc75e85 --- /dev/null +++ b/test/language/statements/class/privatefieldset-typeerror-5.js @@ -0,0 +1,59 @@ +// Copyright (C) 2017 Valerie Young. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: TypeError when setting private field not in `this`'s [[PrivateFieldValues]] +esid: sec-putvalue +info: | + PutValue ( V, W ) + ... + 5. Else if IsPropertyReference(V), then + ... + b. If IsPrivateReference(V), then + i. Let env be the running execution context's PrivateNameEnvironment. + ii. Let field be ? ResolveBinding(GetReferencedName(V), env). + iii. Assert: field is a Private Name. + iv. Perform ? PrivateFieldSet(field, base, W). + + PrivateFieldSet (P, O, value ) + 1. Assert: P is a Private Name value. + 2. If O is not an object, throw a TypeError exception. + 3. Let entry be PrivateFieldFind(P, O). + 4. If entry is empty, throw a TypeError exception. + + PrivateFieldFind (P, O) + 1. Assert: P is a Private Name value. + 2. Assert: O is an object with a [[PrivateFieldValues]] internal slot. + 3. For each element entry in O.[[PrivateFieldValues]], + a. If entry.[[PrivateName]] is P, return entry. + 4. Return empty. + +features: [class-fields] +---*/ + + +class Outer { + #x = 42; + + innerclass() { + var self = this; + + return class extends Outer { + #x = 'not42'; + f() { + self.#x = 1; + } + } + } +} + +var Inner = new Outer().innerclass(); +var i = new Inner(); + +assert.throws(TypeError, function() { + // when f() is called, the entry in the PrivateNameEnironment's environment + // record for '#x' will contain the Inner class's Private Name for '#x'. + // When this Private Name is used for lookup on the `self` object, it + // will not be found (as the `self` object has the Outer's Private Name for #x) + i.f(); +})