summaryrefslogtreecommitdiffstats
path: root/js/src/tests/non262/expressions/short-circuit-compound-assignment.js
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--js/src/tests/non262/expressions/short-circuit-compound-assignment.js265
1 files changed, 265 insertions, 0 deletions
diff --git a/js/src/tests/non262/expressions/short-circuit-compound-assignment.js b/js/src/tests/non262/expressions/short-circuit-compound-assignment.js
new file mode 100644
index 0000000000..c08c4ddecf
--- /dev/null
+++ b/js/src/tests/non262/expressions/short-circuit-compound-assignment.js
@@ -0,0 +1,265 @@
+const testCasesAnd = [];
+const testCasesOr = [];
+const testCasesCoalesce = [];
+
+
+// Assignment to a global variable (JSOp::SetGName).
+var globalVar;
+
+function testAnd_GlobalVar(init, value) {
+ globalVar = init;
+ return [(globalVar &&= value), globalVar];
+}
+testCasesAnd.push(testAnd_GlobalVar);
+
+function testOr_GlobalVar(init, value) {
+ globalVar = init;
+ return [(globalVar ||= value), globalVar];
+}
+testCasesOr.push(testOr_GlobalVar);
+
+function testCoalesce_GlobalVar(init, value) {
+ globalVar = init;
+ return [(globalVar ??= value), globalVar];
+}
+testCasesCoalesce.push(testCoalesce_GlobalVar);
+
+
+// Assignment to a local variable (JSOp::SetLocal).
+function testAnd_LocalVar(init, value) {
+ let v = init;
+ return [(v &&= value), v];
+}
+testCasesAnd.push(testAnd_LocalVar);
+
+function testOr_LocalVar(init, value) {
+ let v = init;
+ return [(v ||= value), v];
+}
+testCasesOr.push(testOr_LocalVar);
+
+function testCoalesce_LocalVar(init, value) {
+ let v = init;
+ return [(v ??= value), v];
+}
+testCasesCoalesce.push(testCoalesce_LocalVar);
+
+
+// Assignment to a parameter (JSOp::SetArg).
+function testAnd_Arg(init, value) {
+ function f(v) {
+ return [(v &&= value), v];
+ }
+ return f(init);
+}
+testCasesAnd.push(testAnd_Arg);
+
+function testOr_Arg(init, value) {
+ function f(v) {
+ return [(v ||= value), v];
+ }
+ return f(init);
+}
+testCasesOr.push(testOr_Arg);
+
+function testCoalesce_Arg(init, value) {
+ function f(v) {
+ return [(v ??= value), v];
+ }
+ return f(init);
+}
+testCasesCoalesce.push(testCoalesce_Arg);
+
+
+// Assignment to a closed over variable (JSOp::SetAliasedVar).
+function testAnd_ClosedOver(init, value) {
+ let v = init;
+ function f() {
+ return (v &&= value);
+ }
+ return [f(), v];
+}
+testCasesAnd.push(testAnd_ClosedOver);
+
+function testOr_ClosedOver(init, value) {
+ let v = init;
+ function f() {
+ return (v ||= value);
+ }
+ return [f(), v];
+}
+testCasesOr.push(testOr_ClosedOver);
+
+function testCoalesce_ClosedOver(init, value) {
+ let v = init;
+ function f() {
+ return (v ??= value);
+ }
+ return [f(), v];
+}
+testCasesCoalesce.push(testCoalesce_ClosedOver);
+
+
+// Assignment to a dynamic name (JSOp::SetName).
+function testAnd_DynamicName(init, value) {
+ eval("var v = init;");
+ return [(v &&= value), v];
+}
+testCasesAnd.push(testAnd_DynamicName);
+
+function testOr_DynamicName(init, value) {
+ eval("var v = init;");
+ return [(v ||= value), v];
+}
+testCasesOr.push(testOr_DynamicName);
+
+function testCoalesce_DynamicName(init, value) {
+ eval("var v = init;");
+ return [(v ??= value), v];
+}
+testCasesCoalesce.push(testCoalesce_DynamicName);
+
+
+// Assignment to a property.
+function testAnd_Property(init, value) {
+ let obj = {p: init};
+ return [(obj.p &&= value), obj.p];
+}
+testCasesAnd.push(testAnd_Property);
+
+function testOr_Property(init, value) {
+ let obj = {p: init};
+ return [(obj.p ||= value), obj.p];
+}
+testCasesOr.push(testOr_Property);
+
+function testCoalesce_Property(init, value) {
+ let obj = {p: init};
+ return [(obj.p ??= value), obj.p];
+}
+testCasesCoalesce.push(testCoalesce_Property);
+
+
+// Assignment to a super property.
+function testAnd_SuperProperty(init, value) {
+ let proto = {p: init};
+ let obj = {__proto__: proto, m() { return (super.p &&= value); }};
+ return [obj.m(), obj.p];
+}
+testCasesAnd.push(testAnd_SuperProperty);
+
+function testOr_SuperProperty(init, value) {
+ let proto = {p: init};
+ let obj = {__proto__: proto, m() { return (super.p ||= value); }};
+ return [obj.m(), obj.p];
+}
+testCasesOr.push(testOr_SuperProperty);
+
+function testCoalesce_SuperProperty(init, value) {
+ let proto = {p: init};
+ let obj = {__proto__: proto, m() { return (super.p ??= value); }};
+ return [obj.m(), obj.p];
+}
+testCasesCoalesce.push(testCoalesce_SuperProperty);
+
+
+// Assignment to an element.
+function testAnd_Element(init, value) {
+ let p = 123;
+ let obj = {[p]: init};
+ return [(obj[p] &&= value), obj[p]];
+}
+testCasesAnd.push(testAnd_Element);
+
+function testOr_Element(init, value) {
+ let p = 123;
+ let obj = {[p]: init};
+ return [(obj[p] ||= value), obj[p]];
+}
+testCasesOr.push(testOr_Element);
+
+function testCoalesce_Element(init, value) {
+ let p = 123;
+ let obj = {[p]: init};
+ return [(obj[p] ??= value), obj[p]];
+}
+testCasesCoalesce.push(testCoalesce_Element);
+
+
+// Assignment to a super element.
+function testAnd_SuperElement(init, value) {
+ let p = 123;
+ let proto = {[p]: init};
+ let obj = {__proto__: proto, m() { return (super[p] &&= value); }};
+ return [obj.m(), obj[p]];
+}
+testCasesAnd.push(testAnd_SuperElement);
+
+function testOr_SuperElement(init, value) {
+ let p = 123;
+ let proto = {[p]: init};
+ let obj = {__proto__: proto, m() { return (super[p] ||= value); }};
+ return [obj.m(), obj[p]];
+}
+testCasesOr.push(testOr_SuperElement);
+
+function testCoalesce_SuperElement(init, value) {
+ let p = 123;
+ let proto = {[p]: init};
+ let obj = {__proto__: proto, m() { return (super[p] ??= value); }};
+ return [obj.m(), obj[p]];
+}
+testCasesCoalesce.push(testCoalesce_SuperElement);
+
+
+// Run the actual tests.
+
+function runTest(testCases, init, value, expected) {
+ for (let f of testCases) {
+ let [result, newValue] = f(init, value);
+
+ assertEq(result, expected);
+ assertEq(newValue, expected);
+ }
+}
+
+function testAnd(init, value) {
+ const expected = init ? value : init;
+ runTest(testCasesAnd, init, value, expected);
+}
+
+function testOr(init, value) {
+ const expected = !init ? value : init;
+ runTest(testCasesOr, init, value, expected);
+}
+
+function testCoalesce(init, value) {
+ const expected = init === undefined || init === null ? value : init;
+ runTest(testCasesCoalesce, init, value, expected);
+}
+
+
+// Repeat a number of times to ensure JITs can kick in, too.
+for (let i = 0; i < 50; ++i) {
+ for (let thruthy of [true, 123, 123n, "hi", [], Symbol()]) {
+ testAnd(thruthy, "pass");
+ testOr(thruthy, "fail");
+ testCoalesce(thruthy, "fail");
+ }
+
+ for (let falsy of [false, 0, NaN, 0n, ""]) {
+ testAnd(falsy, "fail");
+ testOr(falsy, "pass");
+ testCoalesce(falsy, "fail");
+ }
+
+ for (let nullOrUndefined of [null, undefined]) {
+ testAnd(nullOrUndefined, "fail");
+ testOr(nullOrUndefined, "pass");
+ testCoalesce(nullOrUndefined, "pass");
+ }
+}
+
+
+if (typeof reportCompare === "function")
+ reportCompare(0, 0);