diff --git a/test/language/expressions/logical-assignment/lgcl-and-assignment-operator-bigint.js b/test/language/expressions/logical-assignment/lgcl-and-assignment-operator-bigint.js new file mode 100644 index 0000000000..f211488898 --- /dev/null +++ b/test/language/expressions/logical-assignment/lgcl-and-assignment-operator-bigint.js @@ -0,0 +1,27 @@ +// Copyright (c) 2020 Ecma International. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-assignment-operators-runtime-semantics-evaluation +description: Logical And Assignment Operator +features: [BigInt] +info: | + AssignmentExpression: + LeftHandSideExpression &&= AssignmentExpression + + 1. Let lref be the result of evaluating LeftHandSideExpression. + 2. Let lval be ? GetValue(lref). + 3. Let lbool be ! ToBoolean(lval). + 4. If lbool is false, return lval. + 5. Let rref be the result of evaluating AssignmentExpression. + 6. Let rval be ? GetValue(rref). + 7. Perform ? PutValue(lref, rval). + 8. Return rval. + +---*/ + +var value = 0n; +assert.sameValue(value &&= 1n, "test", "(value &&= 1n) === 0n; where value = 0n"); + +var value = 2n; +assert.sameValue(value &&= 1n, "test", "(value &&= 1n) === 1n; where value = 2n"); diff --git a/test/language/expressions/logical-assignment/lgcl-and-assignment-operator-lhs-before-rhs.js b/test/language/expressions/logical-assignment/lgcl-and-assignment-operator-lhs-before-rhs.js new file mode 100644 index 0000000000..1260bf011b --- /dev/null +++ b/test/language/expressions/logical-assignment/lgcl-and-assignment-operator-lhs-before-rhs.js @@ -0,0 +1,52 @@ +// Copyright (c) 2020 Ecma International. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-assignment-operators-runtime-semantics-evaluation +description: > + The LeftHandSideExpression is evaluated before the AssignmentExpression. + +---*/ + +function DummyError() { } + +assert.throws(DummyError, function() { + var base = null; + var prop = function() { + throw new DummyError(); + }; + var expr = function() { + throw new Test262Error("right-hand side expression evaluated"); + }; + + base[prop()] &&= expr(); +}); + +assert.throws(Test262Error, function() { + var base = null; + var prop = { + toString: function() { + throw new Test262Error("property key evaluated"); + } + }; + var expr = function() { + throw new Test262Error("right-hand side expression evaluated"); + }; + + base[prop] &&= expr(); +}); + +var count = 0; +var obj = {}; +function incr() { + return ++count; +} + +assert.sameValue(obj[incr()] &&= incr(), undefined, "obj[incr()] &&= incr()"); +assert.sameValue(obj[1], undefined, "obj[1]"); +assert.sameValue(count, 1, "count"); + +obj[2] = 1; +assert.sameValue(obj[incr()] &&= incr(), 3, "obj[incr()] &&= incr()"); +assert.sameValue(obj[2], 3, "obj[2]"); +assert.sameValue(count, 3, "count"); diff --git a/test/language/expressions/logical-assignment/lgcl-and-assignment-operator-no-set-put.js b/test/language/expressions/logical-assignment/lgcl-and-assignment-operator-no-set-put.js new file mode 100644 index 0000000000..f4aef21b24 --- /dev/null +++ b/test/language/expressions/logical-assignment/lgcl-and-assignment-operator-no-set-put.js @@ -0,0 +1,27 @@ +// Copyright (c) 2020 Ecma International. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-assignment-operators-runtime-semantics-evaluation +description: > + Strict Mode - TypeError is thrown if the LeftHandSide of a Logical + Assignment operator(&&=) is a reference to a data property with the + attribute value {[[Set]]:undefined} and PutValue step is reached. +flags: [onlyStrict] + +---*/ + +var obj = {}; +Object.defineProperty(obj, "prop", { + get: function() { + return 2; + }, + set: undefined, + enumerable: true, + configurable: true +}); + +assert.throws(ReferenceError, function() { + obj.prop &&= 1; +}); +assert.sameValue(obj.prop, 2, "obj.prop"); diff --git a/test/language/expressions/logical-assignment/lgcl-and-assignment-operator-no-set.js b/test/language/expressions/logical-assignment/lgcl-and-assignment-operator-no-set.js new file mode 100644 index 0000000000..5a7422c389 --- /dev/null +++ b/test/language/expressions/logical-assignment/lgcl-and-assignment-operator-no-set.js @@ -0,0 +1,24 @@ +// Copyright (c) 2020 Ecma International. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-assignment-operators-runtime-semantics-evaluation +description: > + Strict Mode - TypeError is not thrown if the LeftHandSide of a Logical + Assignment operator(&&=) is a reference to a data property with the + attribute value {[[Set]]:undefined} and PutValue step is not reached. +flags: [onlyStrict] + +---*/ + +var obj = {}; +Object.defineProperty(obj, "prop", { + get: function() { + return 0; + }, + set: undefined, + enumerable: true, + configurable: true +}); + +assert.sameValue(obj.prop &&= 1, 0, "obj.prop"); diff --git a/test/language/expressions/logical-assignment/lgcl-and-assignment-operator-non-extensible.js b/test/language/expressions/logical-assignment/lgcl-and-assignment-operator-non-extensible.js new file mode 100644 index 0000000000..3eb07bacb9 --- /dev/null +++ b/test/language/expressions/logical-assignment/lgcl-and-assignment-operator-non-extensible.js @@ -0,0 +1,18 @@ +// Copyright (c) 2020 Ecma International. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-assignment-operators-runtime-semantics-evaluation +description: > + Strict Mode - TypeError is not thrown if The LeftHandSide of a Logical + Assignment operator(&&=) is a reference to a non-existent property of an + object whose [[Extensible]] internal property is false. +flags: [onlyStrict] + +---*/ + +var obj = {}; +Object.preventExtensions(obj); + +obj.prop &&= 1; +assert.sameValue(obj.prop, undefined, "obj.prop"); diff --git a/test/language/expressions/logical-assignment/lgcl-and-assignment-operator-non-simple-lhs.js b/test/language/expressions/logical-assignment/lgcl-and-assignment-operator-non-simple-lhs.js new file mode 100644 index 0000000000..edbf690944 --- /dev/null +++ b/test/language/expressions/logical-assignment/lgcl-and-assignment-operator-non-simple-lhs.js @@ -0,0 +1,18 @@ +// Copyright (c) 2020 Ecma International. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-assignment-operators-static-semantics-early-errors +description: > + It is a Syntax Error if AssignmentTargetType of LeftHandSideExpression is + not simple. +negative: + phase: parse + type: SyntaxError + +---*/ + +$DONOTEVALUATE(); + +function test() {} +test() &&= 1; diff --git a/test/language/expressions/logical-assignment/lgcl-and-assignment-operator-non-writeable-put.js b/test/language/expressions/logical-assignment/lgcl-and-assignment-operator-non-writeable-put.js new file mode 100644 index 0000000000..c4273da859 --- /dev/null +++ b/test/language/expressions/logical-assignment/lgcl-and-assignment-operator-non-writeable-put.js @@ -0,0 +1,25 @@ +// Copyright (c) 2020 Ecma International. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-assignment-operators-runtime-semantics-evaluation +description: > + Strict Mode - TypeError is thrown if the LeftHandSide of a Logical + Assignment operator(&&=) is a reference to a data property with the + attribute value {[[Writable]]:false} and PutValue step is reached. +flags: [onlyStrict] + +---*/ + +var obj = {}; +Object.defineProperty(obj, "prop", { + value: 2, + writable: false, + enumerable: true, + configurable: true +}); + +assert.throws(ReferenceError, function() { + obj.prop &&= 1; +}); +assert.sameValue(obj.prop, 2, "obj.prop"); diff --git a/test/language/expressions/logical-assignment/lgcl-and-assignment-operator-non-writeable.js b/test/language/expressions/logical-assignment/lgcl-and-assignment-operator-non-writeable.js new file mode 100644 index 0000000000..54d4eed678 --- /dev/null +++ b/test/language/expressions/logical-assignment/lgcl-and-assignment-operator-non-writeable.js @@ -0,0 +1,22 @@ +// Copyright (c) 2020 Ecma International. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-assignment-operators-runtime-semantics-evaluation +description: > + Strict Mode - TypeError is not thrown if the LeftHandSide of a Logical + Assignment operator(&&=) is a reference to a data property with the + attribute value {[[Writable]]:false} and PutValue step is not reached. +flags: [onlyStrict] + +---*/ + +var obj = {}; +Object.defineProperty(obj, "prop", { + value: 0, + writable: false, + enumerable: true, + configurable: true +}); + +assert.sameValue(obj.prop &&= 1, 0, "obj.prop"); diff --git a/test/language/expressions/logical-assignment/lgcl-and-assignment-operator-unresolved-lhs.js b/test/language/expressions/logical-assignment/lgcl-and-assignment-operator-unresolved-lhs.js new file mode 100644 index 0000000000..596805130f --- /dev/null +++ b/test/language/expressions/logical-assignment/lgcl-and-assignment-operator-unresolved-lhs.js @@ -0,0 +1,15 @@ +// Copyright (c) 2020 Ecma International. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-assignment-operators-runtime-semantics-evaluation +description: > + ReferenceError is thrown if the LeftHandSideExpression of a Logical + Assignment operator(&&=) evaluates to an unresolvable reference +flags: [onlyStrict] + +---*/ + +assert.throws(ReferenceError, function() { + unresolved &&= 1; +}); diff --git a/test/language/expressions/logical-assignment/lgcl-and-assignment-operator-unresolved-rhs-put.js b/test/language/expressions/logical-assignment/lgcl-and-assignment-operator-unresolved-rhs-put.js new file mode 100644 index 0000000000..156960b4a3 --- /dev/null +++ b/test/language/expressions/logical-assignment/lgcl-and-assignment-operator-unresolved-rhs-put.js @@ -0,0 +1,18 @@ +// Copyright (c) 2020 Ecma International. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-assignment-operators-runtime-semantics-evaluation +description: > + ReferenceError is thrown if the AssignmentExpression of a Logical + Assignment operator(&&=) evaluates to an unresolvable reference and the + AssignmentExpression is evaluated. + +---*/ + +var value = 2; + +assert.throws(ReferenceError, function() { + value &&= unresolved; +}); +assert.sameValue(value, 2, "value"); diff --git a/test/language/expressions/logical-assignment/lgcl-and-assignment-operator-unresolved-rhs.js b/test/language/expressions/logical-assignment/lgcl-and-assignment-operator-unresolved-rhs.js new file mode 100644 index 0000000000..8443ad3186 --- /dev/null +++ b/test/language/expressions/logical-assignment/lgcl-and-assignment-operator-unresolved-rhs.js @@ -0,0 +1,15 @@ +// Copyright (c) 2020 Ecma International. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-assignment-operators-runtime-semantics-evaluation +description: > + ReferenceError is not thrown if the AssignmentExpression of a Logical + Assignment operator(&&=) evaluates to an unresolvable reference and the + AssignmentExpression is not evaluated. + +---*/ + +var value = 0; + +assert.sameValue(value &&= unresolved, 0, "value"); diff --git a/test/language/expressions/logical-assignment/lgcl-and-assignment-operator.js b/test/language/expressions/logical-assignment/lgcl-and-assignment-operator.js new file mode 100644 index 0000000000..ed2ec69fb4 --- /dev/null +++ b/test/language/expressions/logical-assignment/lgcl-and-assignment-operator.js @@ -0,0 +1,60 @@ +// Copyright (c) 2020 Ecma International. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-assignment-operators-runtime-semantics-evaluation +description: Logical And Assignment Operator +info: | + AssignmentExpression: + LeftHandSideExpression &&= AssignmentExpression + + 1. Let lref be the result of evaluating LeftHandSideExpression. + 2. Let lval be ? GetValue(lref). + 3. Let lbool be ! ToBoolean(lval). + 4. If lbool is false, return lval. + 5. Let rref be the result of evaluating AssignmentExpression. + 6. Let rval be ? GetValue(rref). + 7. Perform ? PutValue(lref, rval). + 8. Return rval. + +---*/ + +var value = undefined; +assert.sameValue(value &&= 1, undefined, "(value &&= 1) === undefined; where value = undefined"); + +value = null; +assert.sameValue(value &&= 1, null, "(value &&= 1) === null where value = null"); + +value = false; +assert.sameValue(value &&= 1, false, "(value &&= 1) === false; where value = false"); + +value = 0; +assert.sameValue(value &&= 1, 0, "(value &&= 1) === 0; where value = 0"); + +value = -0; +assert.sameValue(value &&= 1, -0, "(value &&= 1) === -0; where value = -0"); + +value = NaN; +assert.sameValue(value &&= 1, NaN, "(value &&= 1) === NaN; where value = NaN"); + +value = ""; +assert.sameValue(value &&= 1, "", '(value &&= 1) === "" where value = ""'); + + + +value = true; +assert.sameValue(value &&= 1, 1, "(value &&= 1) === 1; where value = true"); + +value = 2; +assert.sameValue(value &&= 1, 1, "(value &&= 1) === 1; where value = 2"); + +value = "test"; +assert.sameValue(value &&= 1, 1, '(value &&= 1) === 1; where value = "test"'); + +var sym = Symbol(""); +value = sym; +assert.sameValue(value &&= 1, 1, "(value &&= 1) === 1; where value = Symbol()"); + +var obj = {}; +value = obj; +assert.sameValue(value &&= 1, 1, "(value &&= 1) === 1; where value = {}"); diff --git a/test/language/expressions/logical-assignment/lgcl-nullish-assignment-operator-bigint.js b/test/language/expressions/logical-assignment/lgcl-nullish-assignment-operator-bigint.js new file mode 100644 index 0000000000..85cdf851f1 --- /dev/null +++ b/test/language/expressions/logical-assignment/lgcl-nullish-assignment-operator-bigint.js @@ -0,0 +1,26 @@ +// Copyright (c) 2020 Ecma International. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-assignment-operators-runtime-semantics-evaluation +description: Logical Nullish Assignment Operator +features: [BigInt] +info: | + AssignmentExpression: + LeftHandSideExpression ??= AssignmentExpression + + 1. Let lref be the result of evaluating LeftHandSideExpression. + 2. Let lval be ? GetValue(lref). + 3. If lval is neither undefined nor null, return lval. + 4. Let rref be the result of evaluating AssignmentExpression. + 5. Let rval be ? GetValue(rref). + 6. Perform ? PutValue(lref, rval). + 7. Return rval. + +---*/ + +var value = 0n; +assert.sameValue(value ??= 1n, "test", "(value ??= 1n) === 0n; where value = 0n"); + +var value = 2n; +assert.sameValue(value ??= 1n, "test", "(value ??= 1n) === 2n; where value = 2n"); diff --git a/test/language/expressions/logical-assignment/lgcl-nullish-assignment-operator-lhs-before-rhs.js b/test/language/expressions/logical-assignment/lgcl-nullish-assignment-operator-lhs-before-rhs.js new file mode 100644 index 0000000000..bfc46cf10b --- /dev/null +++ b/test/language/expressions/logical-assignment/lgcl-nullish-assignment-operator-lhs-before-rhs.js @@ -0,0 +1,52 @@ +// Copyright (c) 2020 Ecma International. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-assignment-operators-runtime-semantics-evaluation +description: > + The LeftHandSideExpression is evaluated before the AssignmentExpression. + +---*/ + +function DummyError() { } + +assert.throws(DummyError, function() { + var base = null; + var prop = function() { + throw new DummyError(); + }; + var expr = function() { + throw new Test262Error("right-hand side expression evaluated"); + }; + + base[prop()] ??= expr(); +}); + +assert.throws(Test262Error, function() { + var base = null; + var prop = { + toString: function() { + throw new Test262Error("property key evaluated"); + } + }; + var expr = function() { + throw new Test262Error("right-hand side expression evaluated"); + }; + + base[prop] ??= expr(); +}); + +var count = 0; +var obj = {}; +function incr() { + return ++count; +} + +assert.sameValue(obj[incr()] ??= incr(), 2, "obj[incr()] ??= incr()"); +assert.sameValue(obj[1], 2, "obj[1]"); +assert.sameValue(count, 1, "count"); + +obj[2] = 1; +assert.sameValue(obj[incr()] ??= incr(), 3, "obj[incr()] ??= incr()"); +assert.sameValue(obj[3], 1, "obj[3]"); +assert.sameValue(count, 3, "count"); diff --git a/test/language/expressions/logical-assignment/lgcl-nullish-assignment-operator-no-set-put.js b/test/language/expressions/logical-assignment/lgcl-nullish-assignment-operator-no-set-put.js new file mode 100644 index 0000000000..c191a5ac0e --- /dev/null +++ b/test/language/expressions/logical-assignment/lgcl-nullish-assignment-operator-no-set-put.js @@ -0,0 +1,27 @@ +// Copyright (c) 2020 Ecma International. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-assignment-operators-runtime-semantics-evaluation +description: > + Strict Mode - TypeError is thrown if the LeftHandSide of a Logical + Assignment operator(??=) is a reference to a data property with the + attribute value {[[Set]]:undefined} and PutValue step is reached. +flags: [onlyStrict] + +---*/ + +var obj = {}; +Object.defineProperty(obj, "prop", { + get: function() { + return undefined; + }, + set: undefined, + enumerable: true, + configurable: true +}); + +assert.throws(ReferenceError, function() { + obj.prop ??= 1; +}); +assert.sameValue(obj.prop, undefined, "obj.prop"); diff --git a/test/language/expressions/logical-assignment/lgcl-nullish-assignment-operator-no-set.js b/test/language/expressions/logical-assignment/lgcl-nullish-assignment-operator-no-set.js new file mode 100644 index 0000000000..ab574dc708 --- /dev/null +++ b/test/language/expressions/logical-assignment/lgcl-nullish-assignment-operator-no-set.js @@ -0,0 +1,24 @@ +// Copyright (c) 2020 Ecma International. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-assignment-operators-runtime-semantics-evaluation +description: > + Strict Mode - TypeError is not thrown if the LeftHandSide of a Logical + Assignment operator(??=) is a reference to a data property with the + attribute value {[[Set]]:undefined} and PutValue step is not reached. +flags: [onlyStrict] + +---*/ + +var obj = {}; +Object.defineProperty(obj, "prop", { + get: function() { + return 0; + }, + set: undefined, + enumerable: true, + configurable: true +}); + +assert.sameValue(obj.prop ??= 1, 0, "obj.prop"); diff --git a/test/language/expressions/logical-assignment/lgcl-nullish-assignment-operator-non-extensible.js b/test/language/expressions/logical-assignment/lgcl-nullish-assignment-operator-non-extensible.js new file mode 100644 index 0000000000..fceb861c6a --- /dev/null +++ b/test/language/expressions/logical-assignment/lgcl-nullish-assignment-operator-non-extensible.js @@ -0,0 +1,20 @@ +// Copyright (c) 2020 Ecma International. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-assignment-operators-runtime-semantics-evaluation +description: > + Strict Mode - TypeError is thrown if The LeftHandSide of a Logical + Assignment operator(??=) is a reference to a non-existent property + of an object whose [[Extensible]] internal property is false. +flags: [onlyStrict] + +---*/ + +var obj = {}; +Object.preventExtensions(obj); + +assert.throws(ReferenceError, function() { + obj.prop ??= 1; +}); +assert.sameValue(obj.prop, undefined, "obj.prop"); diff --git a/test/language/expressions/logical-assignment/lgcl-nullish-assignment-operator-non-simple-lhs.js b/test/language/expressions/logical-assignment/lgcl-nullish-assignment-operator-non-simple-lhs.js new file mode 100644 index 0000000000..c1cedf69f3 --- /dev/null +++ b/test/language/expressions/logical-assignment/lgcl-nullish-assignment-operator-non-simple-lhs.js @@ -0,0 +1,18 @@ +// Copyright (c) 2020 Ecma International. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-assignment-operators-static-semantics-early-errors +description: > + It is a Syntax Error if AssignmentTargetType of LeftHandSideExpression is + not simple. +negative: + phase: parse + type: SyntaxError + +---*/ + +$DONOTEVALUATE(); + +function test() {} +test() ??= 1; diff --git a/test/language/expressions/logical-assignment/lgcl-nullish-assignment-operator-non-writeable-put.js b/test/language/expressions/logical-assignment/lgcl-nullish-assignment-operator-non-writeable-put.js new file mode 100644 index 0000000000..be55ca97e7 --- /dev/null +++ b/test/language/expressions/logical-assignment/lgcl-nullish-assignment-operator-non-writeable-put.js @@ -0,0 +1,25 @@ +// Copyright (c) 2020 Ecma International. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-assignment-operators-runtime-semantics-evaluation +description: > + Strict Mode - TypeError is thrown if the LeftHandSide of a Logical + Assignment operator(??=) is a reference to a data property with the + attribute value {[[Writable]]:false} and PutValue step is reached. +flags: [onlyStrict] + +---*/ + +var obj = {}; +Object.defineProperty(obj, "prop", { + value: undefined, + writable: false, + enumerable: true, + configurable: true +}); + +assert.throws(ReferenceError, function() { + obj.prop ??= 1; +}); +assert.sameValue(obj.prop, undefined, "obj.prop"); diff --git a/test/language/expressions/logical-assignment/lgcl-nullish-assignment-operator-non-writeable.js b/test/language/expressions/logical-assignment/lgcl-nullish-assignment-operator-non-writeable.js new file mode 100644 index 0000000000..04ec6a926d --- /dev/null +++ b/test/language/expressions/logical-assignment/lgcl-nullish-assignment-operator-non-writeable.js @@ -0,0 +1,22 @@ +// Copyright (c) 2020 Ecma International. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-assignment-operators-runtime-semantics-evaluation +description: > + Strict Mode - TypeError is not thrown if the LeftHandSide of a Logical + Assignment operator(??=) is a reference to a data property with the + attribute value {[[Writable]]:false} and PutValue step is not reached. +flags: [onlyStrict] + +---*/ + +var obj = {}; +Object.defineProperty(obj, "prop", { + value: 0, + writable: false, + enumerable: true, + configurable: true +}); + +assert.sameValue(obj.prop ??= 1, 0, "obj.prop"); diff --git a/test/language/expressions/logical-assignment/lgcl-nullish-assignment-operator-unresolved-lhs.js b/test/language/expressions/logical-assignment/lgcl-nullish-assignment-operator-unresolved-lhs.js new file mode 100644 index 0000000000..28d5ca8f6f --- /dev/null +++ b/test/language/expressions/logical-assignment/lgcl-nullish-assignment-operator-unresolved-lhs.js @@ -0,0 +1,15 @@ +// Copyright (c) 2020 Ecma International. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-assignment-operators-runtime-semantics-evaluation +description: > + ReferenceError is thrown if the LeftHandSideExpression of a Logical + Assignment operator(??=) evaluates to an unresolvable reference +flags: [onlyStrict] + +---*/ + +assert.throws(ReferenceError, function() { + unresolved ??= 1; +}); diff --git a/test/language/expressions/logical-assignment/lgcl-nullish-assignment-operator-unresolved-rhs-put.js b/test/language/expressions/logical-assignment/lgcl-nullish-assignment-operator-unresolved-rhs-put.js new file mode 100644 index 0000000000..b522ea58a5 --- /dev/null +++ b/test/language/expressions/logical-assignment/lgcl-nullish-assignment-operator-unresolved-rhs-put.js @@ -0,0 +1,18 @@ +// Copyright (c) 2020 Ecma International. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-assignment-operators-runtime-semantics-evaluation +description: > + ReferenceError is thrown if the AssignmentExpression of a Logical + Assignment operator(??=) evaluates to an unresolvable reference and the + AssignmentExpression is evaluated. + +---*/ + +var value = undefined; + +assert.throws(ReferenceError, function() { + value ??= unresolved; +}); +assert.sameValue(value, undefined, "value"); diff --git a/test/language/expressions/logical-assignment/lgcl-nullish-assignment-operator-unresolved-rhs.js b/test/language/expressions/logical-assignment/lgcl-nullish-assignment-operator-unresolved-rhs.js new file mode 100644 index 0000000000..543f068185 --- /dev/null +++ b/test/language/expressions/logical-assignment/lgcl-nullish-assignment-operator-unresolved-rhs.js @@ -0,0 +1,15 @@ +// Copyright (c) 2020 Ecma International. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-assignment-operators-runtime-semantics-evaluation +description: > + ReferenceError is not thrown if the AssignmentExpression of a Logical + Assignment operator(??=) evaluates to an unresolvable reference and the + AssignmentExpression is not evaluated. + +---*/ + +var value = 0; + +assert.sameValue(value ??= unresolved, 0, "value"); diff --git a/test/language/expressions/logical-assignment/lgcl-nullish-assignment-operator.js b/test/language/expressions/logical-assignment/lgcl-nullish-assignment-operator.js new file mode 100644 index 0000000000..d35f973dc8 --- /dev/null +++ b/test/language/expressions/logical-assignment/lgcl-nullish-assignment-operator.js @@ -0,0 +1,59 @@ +// Copyright (c) 2020 Ecma International. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-assignment-operators-runtime-semantics-evaluation +description: Logical Nullish Assignment Operator +info: | + AssignmentExpression: + LeftHandSideExpression ??= AssignmentExpression + + 1. Let lref be the result of evaluating LeftHandSideExpression. + 2. Let lval be ? GetValue(lref). + 3. If lval is neither undefined nor null, return lval. + 4. Let rref be the result of evaluating AssignmentExpression. + 5. Let rval be ? GetValue(rref). + 6. Perform ? PutValue(lref, rval). + 7. Return rval. + +---*/ + +var value = undefined; +assert.sameValue(value ??= 1, 1, "(value ??= 1) === 1; where value = undefined"); + +value = null; +assert.sameValue(value ??= 1, 1, "(value ??= 1) === 1; where value = null"); + +value = false; +assert.sameValue(value ??= 1, false, "(value ??= 1) === false; where value = false"); + +value = 0; +assert.sameValue(value ??= 1, 0, "(value ??= 1) === 0; where value = 0"); + +value = -0; +assert.sameValue(value ??= 1, -0, "(value ??= 1) === -0; where value = -0"); + +value = NaN; +assert.sameValue(value ??= 1, NaN, "(value ??= 1) === NaN; where value = NaN"); + +value = ""; +assert.sameValue(value ??= 1, "", '(value ??= 1) === "" where value = ""'); + + + +value = true; +assert.sameValue(value ??= 1, true, "(value ??= 1) === true; where value = true"); + +value = 2; +assert.sameValue(value ??= 1, 2, "(value ??= 1) === 2; where value = 2"); + +value = "test"; +assert.sameValue(value ??= 1, "test", '(value ??= 1) === "test"; where value = "test"'); + +var sym = Symbol(""); +value = sym; +assert.sameValue(value ??= 1, sym, "(value ??= 1) === Symbol(); where value = Symbol()"); + +var obj = {}; +value = obj; +assert.sameValue(value ??= 1, obj, "(value ??= 1) === {}; where value = {}"); diff --git a/test/language/expressions/logical-assignment/lgcl-or-assignment-operator-bigint.js b/test/language/expressions/logical-assignment/lgcl-or-assignment-operator-bigint.js new file mode 100644 index 0000000000..750793d4b0 --- /dev/null +++ b/test/language/expressions/logical-assignment/lgcl-or-assignment-operator-bigint.js @@ -0,0 +1,27 @@ +// Copyright (c) 2020 Ecma International. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-assignment-operators-runtime-semantics-evaluation +description: Logical Or Assignment Operator +features: [BigInt] +info: | + AssignmentExpression: + LeftHandSideExpression ||= AssignmentExpression + + 1. Let lref be the result of evaluating LeftHandSideExpression. + 2. Let lval be ? GetValue(lref). + 3. Let lbool be ! ToBoolean(lval). + 4. If lbool is true, return lval. + 5. Let rref be the result of evaluating AssignmentExpression. + 6. Let rval be ? GetValue(rref). + 7. Perform ? PutValue(lref, rval). + 8. Return rval. + +---*/ + +var value = 0n; +assert.sameValue(value ||= 1n, "test", "(value ||= 1n) === 1n; where value = 0n"); + +var value = 2n; +assert.sameValue(value ||= 1n, "test", "(value ||= 1n) === 2n; where value = 2n"); diff --git a/test/language/expressions/logical-assignment/lgcl-or-assignment-operator-lhs-before-rhs.js b/test/language/expressions/logical-assignment/lgcl-or-assignment-operator-lhs-before-rhs.js new file mode 100644 index 0000000000..01132f2dae --- /dev/null +++ b/test/language/expressions/logical-assignment/lgcl-or-assignment-operator-lhs-before-rhs.js @@ -0,0 +1,52 @@ +// Copyright (c) 2020 Ecma International. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-assignment-operators-runtime-semantics-evaluation +description: > + The LeftHandSideExpression is evaluated before the AssignmentExpression. + +---*/ + +function DummyError() { } + +assert.throws(DummyError, function() { + var base = null; + var prop = function() { + throw new DummyError(); + }; + var expr = function() { + throw new Test262Error("right-hand side expression evaluated"); + }; + + base[prop()] ||= expr(); +}); + +assert.throws(Test262Error, function() { + var base = null; + var prop = { + toString: function() { + throw new Test262Error("property key evaluated"); + } + }; + var expr = function() { + throw new Test262Error("right-hand side expression evaluated"); + }; + + base[prop] ||= expr(); +}); + +var count = 0; +var obj = {}; +function incr() { + return ++count; +} + +assert.sameValue(obj[incr()] ||= incr(), 2, "obj[incr()] ||= incr()"); +assert.sameValue(obj[1], 2, "obj[1]"); +assert.sameValue(count, 2, "count"); + +obj[3] = 1; +assert.sameValue(obj[incr()] ||= incr(), 1, "obj[incr()] ||= incr()"); +assert.sameValue(obj[3], 1, "obj[3]"); +assert.sameValue(count, 3, "count"); diff --git a/test/language/expressions/logical-assignment/lgcl-or-assignment-operator-no-set-put.js b/test/language/expressions/logical-assignment/lgcl-or-assignment-operator-no-set-put.js new file mode 100644 index 0000000000..f4fddb49d4 --- /dev/null +++ b/test/language/expressions/logical-assignment/lgcl-or-assignment-operator-no-set-put.js @@ -0,0 +1,27 @@ +// Copyright (c) 2020 Ecma International. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-assignment-operators-runtime-semantics-evaluation +description: > + Strict Mode - TypeError is thrown if the LeftHandSide of a Logical + Assignment operator(||=) is a reference to a data property with the + attribute value {[[Set]]:undefined} and PutValue step is reached. +flags: [onlyStrict] + +---*/ + +var obj = {}; +Object.defineProperty(obj, "prop", { + get: function() { + return 0; + }, + set: undefined, + enumerable: true, + configurable: true +}); + +assert.throws(ReferenceError, function() { + obj.prop ||= 1; +}); +assert.sameValue(obj.prop, 0, "obj.prop"); diff --git a/test/language/expressions/logical-assignment/lgcl-or-assignment-operator-no-set.js b/test/language/expressions/logical-assignment/lgcl-or-assignment-operator-no-set.js new file mode 100644 index 0000000000..8aeeb8a8da --- /dev/null +++ b/test/language/expressions/logical-assignment/lgcl-or-assignment-operator-no-set.js @@ -0,0 +1,24 @@ +// Copyright (c) 2020 Ecma International. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-assignment-operators-runtime-semantics-evaluation +description: > + Strict Mode - TypeError is not thrown if the LeftHandSide of a Logical + Assignment operator(||=) is a reference to a data property with the + attribute value {[[Set]]:undefined} and PutValue step is not reached. +flags: [onlyStrict] + +---*/ + +var obj = {}; +Object.defineProperty(obj, "prop", { + get: function() { + return 2; + }, + set: undefined, + enumerable: true, + configurable: true +}); + +assert.sameValue(obj.prop ||= 1, 2, "obj.prop"); diff --git a/test/language/expressions/logical-assignment/lgcl-or-assignment-operator-non-extensible.js b/test/language/expressions/logical-assignment/lgcl-or-assignment-operator-non-extensible.js new file mode 100644 index 0000000000..71241ab076 --- /dev/null +++ b/test/language/expressions/logical-assignment/lgcl-or-assignment-operator-non-extensible.js @@ -0,0 +1,20 @@ +// Copyright (c) 2020 Ecma International. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-assignment-operators-runtime-semantics-evaluation +description: > + Strict Mode - TypeError is thrown if The LeftHandSide of a Logical + Assignment operator(||=) is a reference to a non-existent property + of an object whose [[Extensible]] internal property is false. +flags: [onlyStrict] + +---*/ + +var obj = {}; +Object.preventExtensions(obj); + +assert.throws(ReferenceError, function() { + obj.prop ||= 1; +}); +assert.sameValue(obj.prop, undefined, "obj.prop"); diff --git a/test/language/expressions/logical-assignment/lgcl-or-assignment-operator-non-simple-lhs.js b/test/language/expressions/logical-assignment/lgcl-or-assignment-operator-non-simple-lhs.js new file mode 100644 index 0000000000..7dcc8bc563 --- /dev/null +++ b/test/language/expressions/logical-assignment/lgcl-or-assignment-operator-non-simple-lhs.js @@ -0,0 +1,18 @@ +// Copyright (c) 2020 Ecma International. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-assignment-operators-static-semantics-early-errors +description: > + It is a Syntax Error if AssignmentTargetType of LeftHandSideExpression is + not simple. +negative: + phase: parse + type: SyntaxError + +---*/ + +$DONOTEVALUATE(); + +function test() {} +test() ||= 1; diff --git a/test/language/expressions/logical-assignment/lgcl-or-assignment-operator-non-writeable-put.js b/test/language/expressions/logical-assignment/lgcl-or-assignment-operator-non-writeable-put.js new file mode 100644 index 0000000000..23e5631a1b --- /dev/null +++ b/test/language/expressions/logical-assignment/lgcl-or-assignment-operator-non-writeable-put.js @@ -0,0 +1,25 @@ +// Copyright (c) 2020 Ecma International. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-assignment-operators-runtime-semantics-evaluation +description: > + Strict Mode - TypeError is thrown if the LeftHandSide of a Logical + Assignment operator(||=) is a reference to a data property with the + attribute value {[[Writable]]:false} and PutValue step is reached. +flags: [onlyStrict] + +---*/ + +var obj = {}; +Object.defineProperty(obj, "prop", { + value: 0, + writable: false, + enumerable: true, + configurable: true +}); + +assert.throws(ReferenceError, function() { + obj.prop ||= 1; +}); +assert.sameValue(obj.prop, 0, "obj.prop"); diff --git a/test/language/expressions/logical-assignment/lgcl-or-assignment-operator-non-writeable.js b/test/language/expressions/logical-assignment/lgcl-or-assignment-operator-non-writeable.js new file mode 100644 index 0000000000..05fc7a798d --- /dev/null +++ b/test/language/expressions/logical-assignment/lgcl-or-assignment-operator-non-writeable.js @@ -0,0 +1,22 @@ +// Copyright (c) 2020 Ecma International. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-assignment-operators-runtime-semantics-evaluation +description: > + Strict Mode - TypeError is not thrown if the LeftHandSide of a Logical + Assignment operator(||=) is a reference to a data property with the + attribute value {[[Writable]]:false} and PutValue step is not reached. +flags: [onlyStrict] + +---*/ + +var obj = {}; +Object.defineProperty(obj, "prop", { + value: 2, + writable: false, + enumerable: true, + configurable: true +}); + +assert.sameValue(obj.prop ||= 1, 2, "obj.prop"); diff --git a/test/language/expressions/logical-assignment/lgcl-or-assignment-operator-unresolved-lhs.js b/test/language/expressions/logical-assignment/lgcl-or-assignment-operator-unresolved-lhs.js new file mode 100644 index 0000000000..33bf2e3648 --- /dev/null +++ b/test/language/expressions/logical-assignment/lgcl-or-assignment-operator-unresolved-lhs.js @@ -0,0 +1,15 @@ +// Copyright (c) 2020 Ecma International. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-assignment-operators-runtime-semantics-evaluation +description: > + ReferenceError is thrown if the LeftHandSideExpression of a Logical + Assignment operator(||=) evaluates to an unresolvable reference +flags: [onlyStrict] + +---*/ + +assert.throws(ReferenceError, function() { + unresolved ||= 1; +}); diff --git a/test/language/expressions/logical-assignment/lgcl-or-assignment-operator-unresolved-rhs-put.js b/test/language/expressions/logical-assignment/lgcl-or-assignment-operator-unresolved-rhs-put.js new file mode 100644 index 0000000000..fc0993d759 --- /dev/null +++ b/test/language/expressions/logical-assignment/lgcl-or-assignment-operator-unresolved-rhs-put.js @@ -0,0 +1,18 @@ +// Copyright (c) 2020 Ecma International. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-assignment-operators-runtime-semantics-evaluation +description: > + ReferenceError is thrown if the AssignmentExpression of a Logical + Assignment operator(||=) evaluates to an unresolvable reference and the + AssignmentExpression is evaluated. + +---*/ + +var value = 0; + +assert.throws(ReferenceError, function() { + value ||= unresolved; +}); +assert.sameValue(value, 0, "value"); diff --git a/test/language/expressions/logical-assignment/lgcl-or-assignment-operator-unresolved-rhs.js b/test/language/expressions/logical-assignment/lgcl-or-assignment-operator-unresolved-rhs.js new file mode 100644 index 0000000000..501b897e95 --- /dev/null +++ b/test/language/expressions/logical-assignment/lgcl-or-assignment-operator-unresolved-rhs.js @@ -0,0 +1,15 @@ +// Copyright (c) 2020 Ecma International. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-assignment-operators-runtime-semantics-evaluation +description: > + ReferenceError is not thrown if the AssignmentExpression of a Logical + Assignment operator(||=) evaluates to an unresolvable reference and the + AssignmentExpression is not evaluated. + +---*/ + +var value = 2; + +assert.sameValue(value ||= unresolved, 2, "value"); diff --git a/test/language/expressions/logical-assignment/lgcl-or-assignment-operator.js b/test/language/expressions/logical-assignment/lgcl-or-assignment-operator.js new file mode 100644 index 0000000000..a34bbd124c --- /dev/null +++ b/test/language/expressions/logical-assignment/lgcl-or-assignment-operator.js @@ -0,0 +1,60 @@ +// Copyright (c) 2020 Ecma International. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-assignment-operators-runtime-semantics-evaluation +description: Logical Or Assignment Operator +info: | + AssignmentExpression: + LeftHandSideExpression ||= AssignmentExpression + + 1. Let lref be the result of evaluating LeftHandSideExpression. + 2. Let lval be ? GetValue(lref). + 3. Let lbool be ! ToBoolean(lval). + 4. If lbool is true, return lval. + 5. Let rref be the result of evaluating AssignmentExpression. + 6. Let rval be ? GetValue(rref). + 7. Perform ? PutValue(lref, rval). + 8. Return rval. + +---*/ + +var value = undefined; +assert.sameValue(value ||= 1, 1, "(value ||= 1) === 1; where value = undefined"); + +value = null; +assert.sameValue(value ||= 1, 1, "(value ||= 1) === 1; where value = null"); + +value = false; +assert.sameValue(value ||= 1, 1, "(value ||= 1) === 1; where value = false"); + +value = 0; +assert.sameValue(value ||= 1, 1, "(value ||= 1) === 1; where value = 0"); + +value = -0; +assert.sameValue(value ||= 1, 1, "(value ||= 1) === 1; where value = -0"); + +value = NaN; +assert.sameValue(value ||= 1, 1, "(value ||= 1) === 1; where value = NaN"); + +value = ""; +assert.sameValue(value ||= 1, 1, '(value ||= 1) === 1; where value = ""'); + + + +value = true; +assert.sameValue(value ||= 1, true, "(value ||= 1) === true; where value = true"); + +value = 2; +assert.sameValue(value ||= 1, 2, "(value ||= 1) === 2; where value = 2"); + +value = "test"; +assert.sameValue(value ||= 1, "test", '(value ||= 1) === "test"; where value = "test"'); + +var sym = Symbol(""); +value = sym; +assert.sameValue(value ||= 1, sym, "(value ||= 1) === Symbol(); where value = Symbol()"); + +var obj = {}; +value = obj; +assert.sameValue(value ||= 1, obj, "(value ||= 1) === {}; where value = {}");