Diff
Modified: trunk/JSTests/ChangeLog (260118 => 260119)
--- trunk/JSTests/ChangeLog 2020-04-15 06:20:39 UTC (rev 260118)
+++ trunk/JSTests/ChangeLog 2020-04-15 07:02:55 UTC (rev 260119)
@@ -1,3 +1,22 @@
+2020-04-15 Devin Rousso <[email protected]>
+
+ [ESNext] Implement logical assignment operators
+ https://bugs.webkit.org/show_bug.cgi?id=209716
+
+ Reviewed by Ross Kirsling.
+
+ * stress/logical-assignment-operator-and.js: Added.
+ * stress/logical-assignment-operator-nullish.js: Added.
+ * stress/logical-assignment-operator-or.js: Added.
+
+ * test262/config.yaml:
+ * test262/expectations.yaml:
+ Right now, test262 expects an early error to be thrown if the lhs is not simple, which does
+ not match what we do with other read-modify assignment operators. This is likely to change
+ in the future to match existing behavior (throw a `ReferenceError`) [1].
+
+ [1]: <https://github.com/tc39/ecma262/issues/257#issuecomment-502878708>
+
2020-04-14 Saam Barati <[email protected]>
Skip all low executable memory wasm tests on arm64
Added: trunk/JSTests/stress/logical-assignment-operator-and.js (0 => 260119)
--- trunk/JSTests/stress/logical-assignment-operator-and.js (rev 0)
+++ trunk/JSTests/stress/logical-assignment-operator-and.js 2020-04-15 07:02:55 UTC (rev 260119)
@@ -0,0 +1,1684 @@
+//@ runLogicalAssignmentOperatorsEnabled
+
+function shouldBe(func, expected) {
+ let actual = func();
+ if (typeof expected === "function" ? !(actual instanceof expected) : actual !== expected)
+ throw new Error(`expected ${JSON.stringify(expected)} but got ${JSON.stringify(actual)}`);
+}
+
+function shouldThrow(func, errorType) {
+ let error;
+ try {
+ func();
+ } catch (e) {
+ error = e;
+ }
+
+ if (!(error instanceof errorType))
+ throw new Error(`Expected ${errorType.name} but saw ${error && error.name}!`);
+}
+
+function shouldThrowSyntaxError(script) {
+ let error;
+ try {
+ eval(script);
+ } catch (e) {
+ error = e;
+ }
+
+ if (!(error instanceof SyntaxError))
+ throw new Error(`Expected SyntaxError but saw ${error && error.name}!`);
+}
+
+shouldBe(function() {
+ let x;
+ return x &&= 42;
+}, undefined);
+
+shouldBe(function() {
+ let x;
+ x &&= 42;
+ return x;
+}, undefined);
+
+shouldBe(function() {
+ let x = undefined;
+ return x &&= 42;
+}, undefined);
+
+shouldBe(function() {
+ let x = undefined;
+ x &&= 42;
+ return x;
+}, undefined);
+
+shouldBe(function() {
+ let x = null;
+ return x &&= 42;
+}, null);
+
+shouldBe(function() {
+ let x = null;
+ x &&= 42;
+ return x;
+}, null);
+
+shouldBe(function() {
+ let x = true;
+ return x &&= 42;
+}, 42);
+
+shouldBe(function() {
+ let x = true;
+ x &&= 42;
+ return x;
+}, 42);
+
+shouldBe(function() {
+ let x = false;
+ return x &&= 42;
+}, false);
+
+shouldBe(function() {
+ let x = false;
+ x &&= 42;
+ return x;
+}, false);
+
+shouldBe(function() {
+ let x = 0;
+ return x &&= 42;
+}, 0);
+
+shouldBe(function() {
+ let x = 0;
+ x &&= 42;
+ return x;
+}, 0);
+
+shouldBe(function() {
+ let x = 1;
+ return x &&= 42;
+}, 42);
+
+shouldBe(function() {
+ let x = 1;
+ x &&= 42;
+ return x;
+}, 42);
+
+shouldBe(function() {
+ let x = "";
+ return x &&= 42;
+}, "");
+
+shouldBe(function() {
+ let x = "";
+ x &&= 42;
+ return x;
+}, "");
+
+shouldBe(function() {
+ let x = "test";
+ return x &&= 42;
+}, 42);
+
+shouldBe(function() {
+ let x = "test";
+ x &&= 42;
+ return x;
+}, 42);
+
+shouldBe(function() {
+ let x = {};
+ return x &&= 42;
+}, 42);
+
+shouldBe(function() {
+ let x = {};
+ x &&= 42;
+ return x;
+}, 42);
+
+shouldBe(function() {
+ let x = [];
+ return x &&= 42;
+}, 42);
+
+shouldBe(function() {
+ let x = [];
+ x &&= 42;
+ return x;
+}, 42);
+
+
+
+shouldBe(function() {
+ const x = undefined;
+ return x &&= 42;
+}, undefined);
+
+shouldBe(function() {
+ const x = undefined;
+ x &&= 42;
+ return x;
+}, undefined);
+
+shouldBe(function() {
+ const x = null;
+ return x &&= 42;
+}, null);
+
+shouldBe(function() {
+ const x = null;
+ x &&= 42;
+ return x;
+}, null);
+
+shouldThrow(function() {
+ const x = true;
+ return x &&= 42;
+}, TypeError);
+
+shouldBe(function() {
+ const x = false;
+ return x &&= 42;
+}, false);
+
+shouldBe(function() {
+ const x = false;
+ x &&= 42;
+ return x;
+}, false);
+
+shouldBe(function() {
+ const x = 0;
+ return x &&= 42;
+}, 0);
+
+shouldBe(function() {
+ const x = 0;
+ x &&= 42;
+ return x;
+}, 0);
+
+shouldThrow(function() {
+ const x = 1;
+ return x &&= 42;
+}, TypeError);
+
+shouldBe(function() {
+ const x = "";
+ return x &&= 42;
+}, "");
+
+shouldBe(function() {
+ const x = "";
+ x &&= 42;
+ return x;
+}, "");
+
+shouldThrow(function() {
+ const x = "test";
+ return x &&= 42;
+}, TypeError);
+
+shouldThrow(function() {
+ const x = {};
+ return x &&= 42;
+}, TypeError);
+
+shouldThrow(function() {
+ const x = [];
+ return x &&= 42;
+}, TypeError);
+
+
+
+shouldBe(function() {
+ let x = {};
+ return x.a &&= 42;
+}, undefined);
+
+shouldBe(function() {
+ let x = {};
+ x.a &&= 42;
+ return x.a;
+}, undefined);
+
+shouldBe(function() {
+ let x = {a: undefined};
+ return x.a &&= 42;
+}, undefined);
+
+shouldBe(function() {
+ let x = {a: undefined};
+ x.a &&= 42;
+ return x.a;
+}, undefined);
+
+shouldBe(function() {
+ let x = {a: null};
+ return x.a &&= 42;
+}, null);
+
+shouldBe(function() {
+ let x = {a: null};
+ x.a &&= 42;
+ return x.a;
+}, null);
+
+shouldBe(function() {
+ let x = {a: true};
+ return x.a &&= 42;
+}, 42);
+
+shouldBe(function() {
+ let x = {a: true};
+ x.a &&= 42;
+ return x.a;
+}, 42);
+
+shouldBe(function() {
+ let x = {a: false};
+ return x.a &&= 42;
+}, false);
+
+shouldBe(function() {
+ let x = {a: false};
+ x.a &&= 42;
+ return x.a;
+}, false);
+
+shouldBe(function() {
+ let x = {a: 0};
+ return x.a &&= 42;
+}, 0);
+
+shouldBe(function() {
+ let x = {a: 0};
+ x.a &&= 42;
+ return x.a;
+}, 0);
+
+shouldBe(function() {
+ let x = {a: 1};
+ return x.a &&= 42;
+}, 42);
+
+shouldBe(function() {
+ let x = {a: 1};
+ x.a &&= 42;
+ return x.a;
+}, 42);
+
+shouldBe(function() {
+ let x = {a: ""};
+ return x.a &&= 42;
+}, "");
+
+shouldBe(function() {
+ let x = {a: ""};
+ x.a &&= 42;
+ return x.a;
+}, "");
+
+shouldBe(function() {
+ let x = {a: "test"};
+ return x.a &&= 42;
+}, 42);
+
+shouldBe(function() {
+ let x = {a: "test"};
+ x.a &&= 42;
+ return x.a;
+}, 42);
+
+shouldBe(function() {
+ let x = {a: {}};
+ return x.a &&= 42;
+}, 42);
+
+shouldBe(function() {
+ let x = {a: {}};
+ x.a &&= 42;
+ return x.a;
+}, 42);
+
+shouldBe(function() {
+ let x = {a: []};
+ return x.a &&= 42;
+}, 42);
+
+shouldBe(function() {
+ let x = {a: []};
+ x.a &&= 42;
+ return x.a;
+}, 42);
+
+
+
+shouldBe(function() {
+ const x = {};
+ return x.a &&= 42;
+}, undefined);
+
+shouldBe(function() {
+ const x = {};
+ x.a &&= 42;
+ return x.a;
+}, undefined);
+
+shouldBe(function() {
+ const x = {a: undefined};
+ return x.a &&= 42;
+}, undefined);
+
+shouldBe(function() {
+ const x = {a: undefined};
+ x.a &&= 42;
+ return x.a;
+}, undefined);
+
+shouldBe(function() {
+ const x = {a: null};
+ return x.a &&= 42;
+}, null);
+
+shouldBe(function() {
+ const x = {a: null};
+ x.a &&= 42;
+ return x.a;
+}, null);
+
+shouldBe(function() {
+ const x = {a: true};
+ return x.a &&= 42;
+}, 42);
+
+shouldBe(function() {
+ const x = {a: true};
+ x.a &&= 42;
+ return x.a;
+}, 42);
+
+shouldBe(function() {
+ const x = {a: false};
+ return x.a &&= 42;
+}, false);
+
+shouldBe(function() {
+ const x = {a: false};
+ x.a &&= 42;
+ return x.a;
+}, false);
+
+shouldBe(function() {
+ const x = {a: 0};
+ return x.a &&= 42;
+}, 0);
+
+shouldBe(function() {
+ const x = {a: 0};
+ x.a &&= 42;
+ return x.a;
+}, 0);
+
+shouldBe(function() {
+ const x = {a: 1};
+ return x.a &&= 42;
+}, 42);
+
+shouldBe(function() {
+ const x = {a: 1};
+ x.a &&= 42;
+ return x.a;
+}, 42);
+
+shouldBe(function() {
+ const x = {a: ""};
+ return x.a &&= 42;
+}, "");
+
+shouldBe(function() {
+ const x = {a: ""};
+ x.a &&= 42;
+ return x.a;
+}, "");
+
+shouldBe(function() {
+ const x = {a: "test"};
+ return x.a &&= 42;
+}, 42);
+
+shouldBe(function() {
+ const x = {a: "test"};
+ x.a &&= 42;
+ return x.a;
+}, 42);
+
+shouldBe(function() {
+ const x = {a: {}};
+ return x.a &&= 42;
+}, 42);
+
+shouldBe(function() {
+ const x = {a: {}};
+ x.a &&= 42;
+ return x.a;
+}, 42);
+
+shouldBe(function() {
+ const x = {a: []};
+ return x.a &&= 42;
+}, 42);
+
+shouldBe(function() {
+ const x = {a: []};
+ x.a &&= 42;
+ return x.a;
+}, 42);
+
+
+
+shouldBe(function() {
+ let x = {};
+ return x["a"] &&= 42;
+}, undefined);
+
+shouldBe(function() {
+ let x = {};
+ x["a"] &&= 42;
+ return x["a"];
+}, undefined);
+
+shouldBe(function() {
+ let x = {a: undefined};
+ return x["a"] &&= 42;
+}, undefined);
+
+shouldBe(function() {
+ let x = {a: undefined};
+ x["a"] &&= 42;
+ return x["a"];
+}, undefined);
+
+shouldBe(function() {
+ let x = {a: null};
+ return x["a"] &&= 42;
+}, null);
+
+shouldBe(function() {
+ let x = {a: null};
+ x["a"] &&= 42;
+ return x["a"];
+}, null);
+
+shouldBe(function() {
+ let x = {a: true};
+ return x["a"] &&= 42;
+}, 42);
+
+shouldBe(function() {
+ let x = {a: true};
+ x["a"] &&= 42;
+ return x["a"];
+}, 42);
+
+shouldBe(function() {
+ let x = {a: false};
+ return x["a"] &&= 42;
+}, false);
+
+shouldBe(function() {
+ let x = {a: false};
+ x["a"] &&= 42;
+ return x["a"];
+}, false);
+
+shouldBe(function() {
+ let x = {a: 0};
+ return x["a"] &&= 42;
+}, 0);
+
+shouldBe(function() {
+ let x = {a: 0};
+ x["a"] &&= 42;
+ return x["a"];
+}, 0);
+
+shouldBe(function() {
+ let x = {a: 1};
+ return x["a"] &&= 42;
+}, 42);
+
+shouldBe(function() {
+ let x = {a: 1};
+ x["a"] &&= 42;
+ return x["a"];
+}, 42);
+
+shouldBe(function() {
+ let x = {a: ""};
+ return x["a"] &&= 42;
+}, "");
+
+shouldBe(function() {
+ let x = {a: ""};
+ x["a"] &&= 42;
+ return x["a"];
+}, "");
+
+shouldBe(function() {
+ let x = {a: "test"};
+ return x["a"] &&= 42;
+}, 42);
+
+shouldBe(function() {
+ let x = {a: "test"};
+ x["a"] &&= 42;
+ return x["a"];
+}, 42);
+
+shouldBe(function() {
+ let x = {a: {}};
+ return x["a"] &&= 42;
+}, 42);
+
+shouldBe(function() {
+ let x = {a: {}};
+ x["a"] &&= 42;
+ return x["a"];
+}, 42);
+
+shouldBe(function() {
+ let x = {a: []};
+ return x["a"] &&= 42;
+}, 42);
+
+shouldBe(function() {
+ let x = {a: []};
+ x["a"] &&= 42;
+ return x["a"];
+}, 42);
+
+
+
+shouldBe(function() {
+ const x = {};
+ return x["a"] &&= 42;
+}, undefined);
+
+shouldBe(function() {
+ const x = {};
+ x["a"] &&= 42;
+ return x["a"];
+}, undefined);
+
+shouldBe(function() {
+ const x = {a: undefined};
+ return x["a"] &&= 42;
+}, undefined);
+
+shouldBe(function() {
+ const x = {a: undefined};
+ x["a"] &&= 42;
+ return x["a"];
+}, undefined);
+
+shouldBe(function() {
+ const x = {a: null};
+ return x["a"] &&= 42;
+}, null);
+
+shouldBe(function() {
+ const x = {a: null};
+ x["a"] &&= 42;
+ return x["a"];
+}, null);
+
+shouldBe(function() {
+ const x = {a: true};
+ return x["a"] &&= 42;
+}, 42);
+
+shouldBe(function() {
+ const x = {a: true};
+ x["a"] &&= 42;
+ return x["a"];
+}, 42);
+
+shouldBe(function() {
+ const x = {a: false};
+ return x["a"] &&= 42;
+}, false);
+
+shouldBe(function() {
+ const x = {a: false};
+ x["a"] &&= 42;
+ return x["a"];
+}, false);
+
+shouldBe(function() {
+ const x = {a: 0};
+ return x["a"] &&= 42;
+}, 0);
+
+shouldBe(function() {
+ const x = {a: 0};
+ x["a"] &&= 42;
+ return x["a"];
+}, 0);
+
+shouldBe(function() {
+ const x = {a: 1};
+ return x["a"] &&= 42;
+}, 42);
+
+shouldBe(function() {
+ const x = {a: 1};
+ x["a"] &&= 42;
+ return x["a"];
+}, 42);
+
+shouldBe(function() {
+ const x = {a: ""};
+ return x["a"] &&= 42;
+}, "");
+
+shouldBe(function() {
+ const x = {a: ""};
+ x["a"] &&= 42;
+ return x["a"];
+}, "");
+
+shouldBe(function() {
+ const x = {a: "test"};
+ return x["a"] &&= 42;
+}, 42);
+
+shouldBe(function() {
+ const x = {a: "test"};
+ x["a"] &&= 42;
+ return x["a"];
+}, 42);
+
+shouldBe(function() {
+ const x = {a: {}};
+ return x["a"] &&= 42;
+}, 42);
+
+shouldBe(function() {
+ const x = {a: {}};
+ x["a"] &&= 42;
+ return x["a"];
+}, 42);
+
+shouldBe(function() {
+ const x = {a: []};
+ return x["a"] &&= 42;
+}, 42);
+
+shouldBe(function() {
+ const x = {a: []};
+ x["a"] &&= 42;
+ return x["a"];
+}, 42);
+
+
+
+shouldBe(function() {
+ let x = [];
+ return x[0] &&= 42;
+}, undefined);
+
+shouldBe(function() {
+ let x = [];
+ x[0] &&= 42;
+ return x[0];
+}, undefined);
+
+shouldBe(function() {
+ let x = [undefined];
+ return x[0] &&= 42;
+}, undefined);
+
+shouldBe(function() {
+ let x = [undefined];
+ x[0] &&= 42;
+ return x[0];
+}, undefined);
+
+shouldBe(function() {
+ let x = [null];
+ return x[0] &&= 42;
+}, null);
+
+shouldBe(function() {
+ let x = [null];
+ x[0] &&= 42;
+ return x[0];
+}, null);
+
+shouldBe(function() {
+ let x = [true];
+ return x[0] &&= 42;
+}, 42);
+
+shouldBe(function() {
+ let x = [true];
+ x[0] &&= 42;
+ return x[0];
+}, 42);
+
+shouldBe(function() {
+ let x = [false];
+ return x[0] &&= 42;
+}, false);
+
+shouldBe(function() {
+ let x = [false];
+ x[0] &&= 42;
+ return x[0];
+}, false);
+
+shouldBe(function() {
+ let x = [0];
+ return x[0] &&= 42;
+}, 0);
+
+shouldBe(function() {
+ let x = [0];
+ x[0] &&= 42;
+ return x[0];
+}, 0);
+
+shouldBe(function() {
+ let x = [1];
+ return x[0] &&= 42;
+}, 42);
+
+shouldBe(function() {
+ let x = [1];
+ x[0] &&= 42;
+ return x[0];
+}, 42);
+
+shouldBe(function() {
+ let x = [""];
+ return x[0] &&= 42;
+}, "");
+
+shouldBe(function() {
+ let x = [""];
+ x[0] &&= 42;
+ return x[0];
+}, "");
+
+shouldBe(function() {
+ let x = ["test"];
+ return x[0] &&= 42;
+}, 42);
+
+shouldBe(function() {
+ let x = ["test"];
+ x[0] &&= 42;
+ return x[0];
+}, 42);
+
+shouldBe(function() {
+ let x = [{}];
+ return x[0] &&= 42;
+}, 42);
+
+shouldBe(function() {
+ let x = [{}];
+ x[0] &&= 42;
+ return x[0];
+}, 42);
+
+shouldBe(function() {
+ let x = [[]];
+ return x[0] &&= 42;
+}, 42);
+
+shouldBe(function() {
+ let x = [[]];
+ x[0] &&= 42;
+ return x[0];
+}, 42);
+
+
+
+shouldBe(function() {
+ const x = [];
+ return x[0] &&= 42;
+}, undefined);
+
+shouldBe(function() {
+ const x = [];
+ x[0] &&= 42;
+ return x[0];
+}, undefined);
+
+shouldBe(function() {
+ const x = [undefined];
+ return x[0] &&= 42;
+}, undefined);
+
+shouldBe(function() {
+ const x = [undefined];
+ x[0] &&= 42;
+ return x[0];
+}, undefined);
+
+shouldBe(function() {
+ const x = [null];
+ return x[0] &&= 42;
+}, null);
+
+shouldBe(function() {
+ const x = [null];
+ x[0] &&= 42;
+ return x[0];
+}, null);
+
+shouldBe(function() {
+ const x = [true];
+ return x[0] &&= 42;
+}, 42);
+
+shouldBe(function() {
+ const x = [true];
+ x[0] &&= 42;
+ return x[0];
+}, 42);
+
+shouldBe(function() {
+ const x = [false];
+ return x[0] &&= 42;
+}, false);
+
+shouldBe(function() {
+ const x = [false];
+ x[0] &&= 42;
+ return x[0];
+}, false);
+
+shouldBe(function() {
+ const x = [0];
+ return x[0] &&= 42;
+}, 0);
+
+shouldBe(function() {
+ const x = [0];
+ x[0] &&= 42;
+ return x[0];
+}, 0);
+
+shouldBe(function() {
+ const x = [1];
+ return x[0] &&= 42;
+}, 42);
+
+shouldBe(function() {
+ const x = [1];
+ x[0] &&= 42;
+ return x[0];
+}, 42);
+
+shouldBe(function() {
+ const x = [""];
+ return x[0] &&= 42;
+}, "");
+
+shouldBe(function() {
+ const x = [""];
+ x[0] &&= 42;
+ return x[0];
+}, "");
+
+shouldBe(function() {
+ const x = ["test"];
+ return x[0] &&= 42;
+}, 42);
+
+shouldBe(function() {
+ const x = ["test"];
+ x[0] &&= 42;
+ return x[0];
+}, 42);
+
+shouldBe(function() {
+ const x = [{}];
+ return x[0] &&= 42;
+}, 42);
+
+shouldBe(function() {
+ const x = [{}];
+ x[0] &&= 42;
+ return x[0];
+}, 42);
+
+shouldBe(function() {
+ const x = [[]];
+ return x[0] &&= 42;
+}, 42);
+
+shouldBe(function() {
+ const x = [[]];
+ x[0] &&= 42;
+ return x[0];
+}, 42);
+
+
+
+shouldBe(function() {
+ let x = false;
+ let y = 1;
+ let z = 2;
+ return x &&= y + z;
+}, false);
+
+shouldBe(function() {
+ let x = false;
+ let y = 1;
+ let z = 2;
+ return x &&= y = z;
+}, false);
+
+shouldBe(function() {
+ let x = false;
+ let y = 1;
+ let z = 2;
+ return x &&= y && z;
+}, false);
+
+shouldBe(function() {
+ let x = false;
+ let y = 1;
+ let z = 2;
+ return x &&= y ?? z;
+}, false);
+
+shouldBe(function() {
+ let x = false;
+ let y = 1;
+ let z = 2;
+ return x &&= y || z;
+}, false);
+
+shouldBe(function() {
+ let x = false;
+ let y = 1;
+ let z = 2;
+ return x &&= y &&= z;
+}, false);
+
+shouldBe(function() {
+ let x = false;
+ let y = 1;
+ let z = 2;
+ return x &&= y ??= z;
+}, false);
+
+shouldBe(function() {
+ let x = false;
+ let y = 1;
+ let z = 2;
+ return x &&= y ||= z;
+}, false);
+
+
+
+shouldBe(function() {
+ let x = true;
+ let y = 1;
+ let z = 2;
+ return x &&= y + z;
+}, 3);
+
+shouldBe(function() {
+ let x = true;
+ let y = 1;
+ let z = 2;
+ return x &&= y = z;
+}, 2);
+
+shouldBe(function() {
+ let x = true;
+ let y = 1;
+ let z = 2;
+ return x &&= y && z;
+}, 2);
+
+shouldBe(function() {
+ let x = true;
+ let y = 1;
+ let z = 2;
+ return x &&= y ?? z;
+}, 1);
+
+shouldBe(function() {
+ let x = true;
+ let y = 1;
+ let z = 2;
+ return x &&= y || z;
+}, 1);
+
+shouldBe(function() {
+ let x = true;
+ let y = 1;
+ let z = 2;
+ return x &&= y &&= z;
+}, 2);
+
+shouldBe(function() {
+ let x = true;
+ let y = 1;
+ let z = 2;
+ return x &&= y ??= z;
+}, 1);
+
+shouldBe(function() {
+ let x = true;
+ let y = 1;
+ let z = 2;
+ return x &&= y ||= z;
+}, 1);
+
+
+
+shouldBe(function() {
+ let log = [];
+
+ let a = true;
+ let x = {
+ get a() {
+ log.push("get");
+ return a;
+ },
+ set a(v) {
+ log.push("set");
+ a = v;
+ },
+ };
+
+ x.a &&= 42;
+ x.a &&= 42;
+
+ return log.join(" ") + " " + a;
+}, "get set get set 42");
+
+shouldBe(function() {
+ let log = [];
+
+ let a = false;
+ let x = {
+ get a() {
+ log.push("get");
+ return a;
+ },
+ set a(v) {
+ log.push("set");
+ a = v;
+ },
+ };
+
+ x.a &&= 42;
+ x.a &&= 42;
+
+ return log.join(" ") + " " + a;
+}, "get get false");
+
+shouldBe(function() {
+ let log = [];
+
+ let a = undefined;
+ let x = {
+ get a() {
+ log.push("get");
+ return a;
+ },
+ set a(v) {
+ log.push("set");
+ a = v;
+ },
+ };
+
+ x.a &&= 42;
+ x.a &&= 42;
+
+ return log.join(" ") + " " + a;
+}, "get get undefined");
+
+
+
+shouldBe(function() {
+ let log = [];
+
+ let a = true;
+ let x = {
+ get a() {
+ log.push("get");
+ return a;
+ },
+ set a(v) {
+ log.push("set");
+ a = v;
+ },
+ };
+
+ x["a"] &&= 42;
+ x["a"] &&= 42;
+
+ return log.join(" ") + " " + a;
+}, "get set get set 42");
+
+shouldBe(function() {
+ let log = [];
+
+ let a = false;
+ let x = {
+ get a() {
+ log.push("get");
+ return a;
+ },
+ set a(v) {
+ log.push("set");
+ a = v;
+ },
+ };
+
+ x["a"] &&= 42;
+ x["a"] &&= 42;
+
+ return log.join(" ") + " " + a;
+}, "get get false");
+
+shouldBe(function() {
+ let log = [];
+
+ let a = undefined;
+ let x = {
+ get a() {
+ log.push("get");
+ return a;
+ },
+ set a(v) {
+ log.push("set");
+ a = v;
+ },
+ };
+
+ x["a"] &&= 42;
+ x["a"] &&= 42;
+
+ return log.join(" ") + " " + a;
+}, "get get undefined");
+
+
+
+shouldBe(function() {
+ let log = [];
+
+ class Parent {
+ get a() {
+ log.push("get-parent");
+ return this._a;
+ }
+ set a(v) {
+ log.push("set-parent");
+ this._a &&= v;
+ }
+ }
+ class Child extends Parent {
+ get a() {
+ log.push("get-child");
+ return super.a;
+ }
+ set a(v) {
+ log.push("set-child");
+ super.a &&= v;
+ }
+ }
+
+ let x = new Child;
+ x._a = true;
+ x.a &&= 42;
+ x.a &&= 42;
+
+ return log.join(" ") + " " + x._a;
+}, "get-child get-parent set-child get-parent set-parent get-child get-parent set-child get-parent set-parent 42");
+
+shouldBe(function() {
+ let log = [];
+
+ class Parent {
+ get a() {
+ log.push("get-parent");
+ return this._a;
+ }
+ set a(v) {
+ log.push("set-parent");
+ this._a &&= v;
+ }
+ }
+ class Child extends Parent {
+ get a() {
+ log.push("get-child");
+ return super.a;
+ }
+ set a(v) {
+ log.push("set-child");
+ super.a &&= v;
+ }
+ }
+
+ let x = new Child;
+ x._a = false;
+ x.a &&= 42;
+ x.a &&= 42;
+
+ return log.join(" ") + " " + x._a;
+}, "get-child get-parent get-child get-parent false");
+
+shouldBe(function() {
+ let log = [];
+
+ class Parent {
+ get a() {
+ log.push("get-parent");
+ return this._a;
+ }
+ set a(v) {
+ log.push("set-parent");
+ this._a &&= v;
+ }
+ }
+ class Child extends Parent {
+ get a() {
+ log.push("get-child");
+ return super.a;
+ }
+ set a(v) {
+ log.push("set-child");
+ super.a &&= v;
+ }
+ }
+
+ let x = new Child;
+ x._a = undefined;
+ x.a &&= 42;
+ x.a &&= 42;
+
+ return log.join(" ") + " " + x._a;
+}, "get-child get-parent get-child get-parent undefined");
+
+
+
+shouldBe(function() {
+ let log = [];
+
+ class Parent {
+ get a() {
+ log.push("get-parent");
+ return this._a;
+ }
+ set a(v) {
+ log.push("set-parent");
+ this._a &&= v;
+ }
+ }
+ class Child extends Parent {
+ get a() {
+ log.push("get-child");
+ return super["a"];
+ }
+ set a(v) {
+ log.push("set-child");
+ super["a"] &&= v;
+ }
+ }
+
+ let x = new Child;
+ x._a = true;
+ x["a"] &&= 42;
+ x["a"] &&= 42;
+
+ return log.join(" ") + " " + x._a;
+}, "get-child get-parent set-child get-parent set-parent get-child get-parent set-child get-parent set-parent 42");
+
+shouldBe(function() {
+ let log = [];
+
+ class Parent {
+ get a() {
+ log.push("get-parent");
+ return this._a;
+ }
+ set a(v) {
+ log.push("set-parent");
+ this._a &&= v;
+ }
+ }
+ class Child extends Parent {
+ get a() {
+ log.push("get-child");
+ return super["a"];
+ }
+ set a(v) {
+ log.push("set-child");
+ super["a"] &&= v;
+ }
+ }
+
+ let x = new Child;
+ x._a = false;
+ x["a"] &&= 42;
+ x["a"] &&= 42;
+
+ return log.join(" ") + " " + x._a;
+}, "get-child get-parent get-child get-parent false");
+
+shouldBe(function() {
+ let log = [];
+
+ class Parent {
+ get a() {
+ log.push("get-parent");
+ return this._a;
+ }
+ set a(v) {
+ log.push("set-parent");
+ this._a &&= v;
+ }
+ }
+ class Child extends Parent {
+ get a() {
+ log.push("get-child");
+ return super["a"];
+ }
+ set a(v) {
+ log.push("set-child");
+ super["a"] &&= v;
+ }
+ }
+
+ let x = new Child;
+ x._a = undefined;
+ x["a"] &&= 42;
+ x["a"] &&= 42;
+
+ return log.join(" ") + " " + x._a;
+}, "get-child get-parent get-child get-parent undefined");
+
+
+
+shouldBe(function() {
+ let x = {};
+ Object.defineProperty(x, "a", {
+ value: true,
+ writable: false,
+ });
+ return x.a &&= 42;
+}, 42);
+
+shouldBe(function() {
+ let x = {};
+ Object.defineProperty(x, "a", {
+ value: false,
+ writable: false,
+ });
+ return x.a &&= 42;
+}, false);
+
+shouldBe(function() {
+ let x = {};
+ Object.defineProperty(x, "a", {
+ value: undefined,
+ writable: false,
+ });
+ return x.a &&= 42;
+}, undefined);
+
+
+
+shouldThrow(function() {
+ "use strict";
+ let x = {};
+ Object.defineProperty(x, "a", {
+ value: true,
+ writable: false,
+ });
+ return x.a &&= 42;
+}, TypeError);
+
+shouldBe(function() {
+ "use strict";
+ let x = {};
+ Object.defineProperty(x, "a", {
+ value: false,
+ writable: false,
+ });
+ return x.a &&= 42;
+}, false);
+
+shouldBe(function() {
+ "use strict";
+ let x = {};
+ Object.defineProperty(x, "a", {
+ value: undefined,
+ writable: false,
+ });
+ return x.a &&= 42;
+}, undefined);
+
+
+
+shouldBe(function() {
+ let x = {};
+ Object.defineProperty(x, "a", {
+ value: true,
+ writable: false,
+ });
+ return x["a"] &&= 42;
+}, 42);
+
+shouldBe(function() {
+ let x = {};
+ Object.defineProperty(x, "a", {
+ value: false,
+ writable: false,
+ });
+ return x["a"] &&= 42;
+}, false);
+
+shouldBe(function() {
+ let x = {};
+ Object.defineProperty(x, "a", {
+ value: undefined,
+ writable: false,
+ });
+ return x["a"] &&= 42;
+}, undefined);
+
+
+
+shouldThrow(function() {
+ "use strict";
+ let x = {};
+ Object.defineProperty(x, "a", {
+ value: true,
+ writable: false,
+ });
+ return x["a"] &&= 42;
+}, TypeError);
+
+shouldBe(function() {
+ "use strict";
+ let x = {};
+ Object.defineProperty(x, "a", {
+ value: false,
+ writable: false,
+ });
+ return x["a"] &&= 42;
+}, false);
+
+shouldBe(function() {
+ "use strict";
+ let x = {};
+ Object.defineProperty(x, "a", {
+ value: undefined,
+ writable: false,
+ });
+ return x["a"] &&= 42;
+}, undefined);
+
+
+
+shouldBe(function() {
+ let x = true;
+ (function() {
+ x &&= 42;
+ })();
+ return x;
+}, 42);
+
+shouldBe(function() {
+ let x = false;
+ return (function() {
+ return x &&= 42;
+ })();
+}, false);
+
+shouldBe(function() {
+ let x = undefined;
+ return (function() {
+ return x &&= 42;
+ })();
+}, undefined);
+
+
+
+shouldThrow(function() {
+ const x = true;
+ (function() {
+ x &&= 42;
+ })();
+ return x;
+}, TypeError);
+
+shouldBe(function() {
+ const x = false;
+ return (function() {
+ return x &&= 42;
+ })();
+}, false);
+
+shouldBe(function() {
+ const x = undefined;
+ return (function() {
+ return x &&= 42;
+ })();
+}, undefined);
+
+
+
+shouldBe(function() {
+ let count = 0;
+
+ const x = true;
+ try {
+ x &&= ++count;
+ } catch { }
+
+ return count;
+}, 1);
+
+shouldBe(function() {
+ let count = 0;
+
+ const x = false;
+ x &&= ++count;
+
+ return count;
+}, 0);
+
+shouldBe(function() {
+ let count = 0;
+
+ const x = undefined;
+ x &&= ++count;
+
+ return count;
+}, 0);
+
+
+
+shouldBe(function() {
+ let count = 0;
+
+ const x = true;
+ function capture() { return x; }
+
+ try {
+ x &&= ++count;
+ } catch { }
+
+ return count;
+}, 1);
+
+shouldBe(function() {
+ let count = 0;
+
+ const x = false;
+ function capture() { return x; }
+
+ x &&= ++count;
+
+ return count;
+}, 0);
+
+shouldBe(function() {
+ let count = 0;
+
+ const x = undefined;
+ function capture() { return x; }
+
+ x &&= ++count;
+
+ return count;
+}, 0);
+
+
+
+shouldThrow(function() {
+ x &&= 42;
+ let x = true;
+ return x;
+}, ReferenceError);
+
+
+
+shouldBe(function() {
+ return undefined &&= 42;
+}, undefined);
+
+shouldThrowSyntaxError(`null &&= 42`);
+
+shouldThrowSyntaxError(`true &&= 42`);
+
+shouldThrowSyntaxError(`false &&= 42`);
+
+shouldThrowSyntaxError(`0 &&= 42`);
+
+shouldThrowSyntaxError(`1 &&= 42`);
+
+shouldThrowSyntaxError(`"" &&= 42`);
+
+shouldThrowSyntaxError(`"test" &&= 42`);
+
+shouldThrowSyntaxError(`{} &&= 42`);
+
+shouldThrowSyntaxError(`[] &&= 42`);
Added: trunk/JSTests/stress/logical-assignment-operator-nullish.js (0 => 260119)
--- trunk/JSTests/stress/logical-assignment-operator-nullish.js (rev 0)
+++ trunk/JSTests/stress/logical-assignment-operator-nullish.js 2020-04-15 07:02:55 UTC (rev 260119)
@@ -0,0 +1,1699 @@
+//@ runLogicalAssignmentOperatorsEnabled
+
+function shouldBe(func, expected) {
+ let actual = func();
+ if (typeof expected === "function" ? !(actual instanceof expected) : actual !== expected)
+ throw new Error(`expected ${JSON.stringify(expected)} but got ${JSON.stringify(actual)}`);
+}
+
+function shouldThrow(func, errorType) {
+ let error;
+ try {
+ func();
+ } catch (e) {
+ error = e;
+ }
+
+ if (!(error instanceof errorType))
+ throw new Error(`Expected ${errorType.name} but saw ${error && error.name}!`);
+}
+
+function shouldThrowSyntaxError(script) {
+ let error;
+ try {
+ eval(script);
+ } catch (e) {
+ error = e;
+ }
+
+ if (!(error instanceof SyntaxError))
+ throw new Error(`Expected SyntaxError but saw ${error && error.name}!`);
+}
+
+shouldBe(function() {
+ let x;
+ return x ??= 42;
+}, 42);
+
+shouldBe(function() {
+ let x;
+ x ??= 42;
+ return x;
+}, 42);
+
+shouldBe(function() {
+ let x = undefined;
+ return x ??= 42;
+}, 42);
+
+shouldBe(function() {
+ let x = undefined;
+ x ??= 42;
+ return x;
+}, 42);
+
+shouldBe(function() {
+ let x = null;
+ return x ??= 42;
+}, 42);
+
+shouldBe(function() {
+ let x = null;
+ x ??= 42;
+ return x;
+}, 42);
+
+shouldBe(function() {
+ let x = true;
+ return x ??= 42;
+}, true);
+
+shouldBe(function() {
+ let x = true;
+ x ??= 42;
+ return x;
+}, true);
+
+shouldBe(function() {
+ let x = false;
+ return x ??= 42;
+}, false);
+
+shouldBe(function() {
+ let x = false;
+ x ??= 42;
+ return x;
+}, false);
+
+shouldBe(function() {
+ let x = 0;
+ return x ??= 42;
+}, 0);
+
+shouldBe(function() {
+ let x = 0;
+ x ??= 42;
+ return x;
+}, 0);
+
+shouldBe(function() {
+ let x = 1;
+ return x ??= 42;
+}, 1);
+
+shouldBe(function() {
+ let x = 1;
+ x ??= 42;
+ return x;
+}, 1);
+
+shouldBe(function() {
+ let x = "";
+ return x ??= 42;
+}, "");
+
+shouldBe(function() {
+ let x = "";
+ x ??= 42;
+ return x;
+}, "");
+
+shouldBe(function() {
+ let x = "test";
+ return x ??= 42;
+}, "test");
+
+shouldBe(function() {
+ let x = "test";
+ x ??= 42;
+ return x;
+}, "test");
+
+shouldBe(function() {
+ let x = {};
+ return x ??= 42;
+}, Object);
+
+shouldBe(function() {
+ let x = {};
+ x ??= 42;
+ return x;
+}, Object);
+
+shouldBe(function() {
+ let x = [];
+ return x ??= 42;
+}, Array);
+
+shouldBe(function() {
+ let x = [];
+ x ??= 42;
+ return x;
+}, Array);
+
+
+
+shouldThrow(function() {
+ const x = undefined;
+ return x ??= 42;
+}, TypeError);
+
+shouldThrow(function() {
+ const x = null;
+ return x ??= 42;
+}, TypeError);
+
+shouldBe(function() {
+ const x = true;
+ return x ??= 42;
+}, true);
+
+shouldBe(function() {
+ const x = true;
+ x ??= 42;
+ return x;
+}, true);
+
+shouldBe(function() {
+ const x = false;
+ return x ??= 42;
+}, false);
+
+shouldBe(function() {
+ const x = false;
+ x ??= 42;
+ return x;
+}, false);
+
+shouldBe(function() {
+ const x = 0;
+ return x ??= 42;
+}, 0);
+
+shouldBe(function() {
+ const x = 0;
+ x ??= 42;
+ return x;
+}, 0);
+
+shouldBe(function() {
+ const x = 1;
+ return x ??= 42;
+}, 1);
+
+shouldBe(function() {
+ const x = 1;
+ x ??= 42;
+ return x;
+}, 1);
+
+shouldBe(function() {
+ const x = "";
+ return x ??= 42;
+}, "");
+
+shouldBe(function() {
+ const x = "";
+ x ??= 42;
+ return x;
+}, "");
+
+shouldBe(function() {
+ const x = "test";
+ return x ??= 42;
+}, "test");
+
+shouldBe(function() {
+ const x = "test";
+ return x ??= 42;
+}, "test");
+
+shouldBe(function() {
+ const x = {};
+ return x ??= 42;
+}, Object);
+
+shouldBe(function() {
+ const x = {};
+ return x ??= 42;
+}, Object);
+
+shouldBe(function() {
+ const x = [];
+ return x ??= 42;
+}, Array);
+
+shouldBe(function() {
+ const x = [];
+ return x ??= 42;
+}, Array);
+
+
+
+shouldBe(function() {
+ let x = {};
+ return x.a ??= 42;
+}, 42);
+
+shouldBe(function() {
+ let x = {};
+ x.a ??= 42;
+ return x.a;
+}, 42);
+
+shouldBe(function() {
+ let x = {a: undefined};
+ return x.a ??= 42;
+}, 42);
+
+shouldBe(function() {
+ let x = {a: undefined};
+ x.a ??= 42;
+ return x.a;
+}, 42);
+
+shouldBe(function() {
+ let x = {a: null};
+ return x.a ??= 42;
+}, 42);
+
+shouldBe(function() {
+ let x = {a: null};
+ x.a ??= 42;
+ return x.a;
+}, 42);
+
+shouldBe(function() {
+ let x = {a: true};
+ return x.a ??= 42;
+}, true);
+
+shouldBe(function() {
+ let x = {a: true};
+ x.a ??= 42;
+ return x.a;
+}, true);
+
+shouldBe(function() {
+ let x = {a: false};
+ return x.a ??= 42;
+}, false);
+
+shouldBe(function() {
+ let x = {a: false};
+ x.a ??= 42;
+ return x.a;
+}, false);
+
+shouldBe(function() {
+ let x = {a: 0};
+ return x.a ??= 42;
+}, 0);
+
+shouldBe(function() {
+ let x = {a: 0};
+ x.a ??= 42;
+ return x.a;
+}, 0);
+
+shouldBe(function() {
+ let x = {a: 1};
+ return x.a ??= 42;
+}, 1);
+
+shouldBe(function() {
+ let x = {a: 1};
+ x.a ??= 42;
+ return x.a;
+}, 1);
+
+shouldBe(function() {
+ let x = {a: ""};
+ return x.a ??= 42;
+}, "");
+
+shouldBe(function() {
+ let x = {a: ""};
+ x.a ??= 42;
+ return x.a;
+}, "");
+
+shouldBe(function() {
+ let x = {a: "test"};
+ return x.a ??= 42;
+}, "test");
+
+shouldBe(function() {
+ let x = {a: "test"};
+ x.a ??= 42;
+ return x.a;
+}, "test");
+
+shouldBe(function() {
+ let x = {a: {}};
+ return x.a ??= 42;
+}, Object);
+
+shouldBe(function() {
+ let x = {a: {}};
+ x.a ??= 42;
+ return x.a;
+}, Object);
+
+shouldBe(function() {
+ let x = {a: []};
+ return x.a ??= 42;
+}, Array);
+
+shouldBe(function() {
+ let x = {a: []};
+ x.a ??= 42;
+ return x.a;
+}, Array);
+
+
+
+shouldBe(function() {
+ const x = {};
+ return x.a ??= 42;
+}, 42);
+
+shouldBe(function() {
+ const x = {};
+ x.a ??= 42;
+ return x.a;
+}, 42);
+
+shouldBe(function() {
+ const x = {a: undefined};
+ return x.a ??= 42;
+}, 42);
+
+shouldBe(function() {
+ const x = {a: undefined};
+ x.a ??= 42;
+ return x.a;
+}, 42);
+
+shouldBe(function() {
+ const x = {a: null};
+ return x.a ??= 42;
+}, 42);
+
+shouldBe(function() {
+ const x = {a: null};
+ x.a ??= 42;
+ return x.a;
+}, 42);
+
+shouldBe(function() {
+ const x = {a: true};
+ return x.a ??= 42;
+}, true);
+
+shouldBe(function() {
+ const x = {a: true};
+ x.a ??= 42;
+ return x.a;
+}, true);
+
+shouldBe(function() {
+ const x = {a: false};
+ return x.a ??= 42;
+}, false);
+
+shouldBe(function() {
+ const x = {a: false};
+ x.a ??= 42;
+ return x.a;
+}, false);
+
+shouldBe(function() {
+ const x = {a: 0};
+ return x.a ??= 42;
+}, 0);
+
+shouldBe(function() {
+ const x = {a: 0};
+ x.a ??= 42;
+ return x.a;
+}, 0);
+
+shouldBe(function() {
+ const x = {a: 1};
+ return x.a ??= 42;
+}, 1);
+
+shouldBe(function() {
+ const x = {a: 1};
+ x.a ??= 42;
+ return x.a;
+}, 1);
+
+shouldBe(function() {
+ const x = {a: ""};
+ return x.a ??= 42;
+}, "");
+
+shouldBe(function() {
+ const x = {a: ""};
+ x.a ??= 42;
+ return x.a;
+}, "");
+
+shouldBe(function() {
+ const x = {a: "test"};
+ return x.a ??= 42;
+}, "test");
+
+shouldBe(function() {
+ const x = {a: "test"};
+ x.a ??= 42;
+ return x.a;
+}, "test");
+
+shouldBe(function() {
+ const x = {a: {}};
+ return x.a ??= 42;
+}, Object);
+
+shouldBe(function() {
+ const x = {a: {}};
+ x.a ??= 42;
+ return x.a;
+}, Object);
+
+shouldBe(function() {
+ const x = {a: []};
+ return x.a ??= 42;
+}, Array);
+
+shouldBe(function() {
+ const x = {a: []};
+ x.a ??= 42;
+ return x.a;
+}, Array);
+
+
+
+shouldBe(function() {
+ let x = {};
+ return x["a"] ??= 42;
+}, 42);
+
+shouldBe(function() {
+ let x = {};
+ x["a"] ??= 42;
+ return x["a"];
+}, 42);
+
+shouldBe(function() {
+ let x = {a: undefined};
+ return x["a"] ??= 42;
+}, 42);
+
+shouldBe(function() {
+ let x = {a: undefined};
+ x["a"] ??= 42;
+ return x["a"];
+}, 42);
+
+shouldBe(function() {
+ let x = {a: null};
+ return x["a"] ??= 42;
+}, 42);
+
+shouldBe(function() {
+ let x = {a: null};
+ x["a"] ??= 42;
+ return x["a"];
+}, 42);
+
+shouldBe(function() {
+ let x = {a: true};
+ return x["a"] ??= 42;
+}, true);
+
+shouldBe(function() {
+ let x = {a: true};
+ x["a"] ??= 42;
+ return x["a"];
+}, true);
+
+shouldBe(function() {
+ let x = {a: false};
+ return x["a"] ??= 42;
+}, false);
+
+shouldBe(function() {
+ let x = {a: false};
+ x["a"] ??= 42;
+ return x["a"];
+}, false);
+
+shouldBe(function() {
+ let x = {a: 0};
+ return x["a"] ??= 42;
+}, 0);
+
+shouldBe(function() {
+ let x = {a: 0};
+ x["a"] ??= 42;
+ return x["a"];
+}, 0);
+
+shouldBe(function() {
+ let x = {a: 1};
+ return x["a"] ??= 42;
+}, 1);
+
+shouldBe(function() {
+ let x = {a: 1};
+ x["a"] ??= 42;
+ return x["a"];
+}, 1);
+
+shouldBe(function() {
+ let x = {a: ""};
+ return x["a"] ??= 42;
+}, "");
+
+shouldBe(function() {
+ let x = {a: ""};
+ x["a"] ??= 42;
+ return x["a"];
+}, "");
+
+shouldBe(function() {
+ let x = {a: "test"};
+ return x["a"] ??= 42;
+}, "test");
+
+shouldBe(function() {
+ let x = {a: "test"};
+ x["a"] ??= 42;
+ return x["a"];
+}, "test");
+
+shouldBe(function() {
+ let x = {a: {}};
+ return x["a"] ??= 42;
+}, Object);
+
+shouldBe(function() {
+ let x = {a: {}};
+ x["a"] ??= 42;
+ return x["a"];
+}, Object);
+
+shouldBe(function() {
+ let x = {a: []};
+ return x["a"] ??= 42;
+}, Array);
+
+shouldBe(function() {
+ let x = {a: []};
+ x["a"] ??= 42;
+ return x["a"];
+}, Array);
+
+
+
+shouldBe(function() {
+ const x = {};
+ return x["a"] ??= 42;
+}, 42);
+
+shouldBe(function() {
+ const x = {};
+ x["a"] ??= 42;
+ return x["a"];
+}, 42);
+
+shouldBe(function() {
+ const x = {a: undefined};
+ return x["a"] ??= 42;
+}, 42);
+
+shouldBe(function() {
+ const x = {a: undefined};
+ x["a"] ??= 42;
+ return x["a"];
+}, 42);
+
+shouldBe(function() {
+ const x = {a: null};
+ return x["a"] ??= 42;
+}, 42);
+
+shouldBe(function() {
+ const x = {a: null};
+ x["a"] ??= 42;
+ return x["a"];
+}, 42);
+
+shouldBe(function() {
+ const x = {a: true};
+ return x["a"] ??= 42;
+}, true);
+
+shouldBe(function() {
+ const x = {a: true};
+ x["a"] ??= 42;
+ return x["a"];
+}, true);
+
+shouldBe(function() {
+ const x = {a: false};
+ return x["a"] ??= 42;
+}, false);
+
+shouldBe(function() {
+ const x = {a: false};
+ x["a"] ??= 42;
+ return x["a"];
+}, false);
+
+shouldBe(function() {
+ const x = {a: 0};
+ return x["a"] ??= 42;
+}, 0);
+
+shouldBe(function() {
+ const x = {a: 0};
+ x["a"] ??= 42;
+ return x["a"];
+}, 0);
+
+shouldBe(function() {
+ const x = {a: 1};
+ return x["a"] ??= 42;
+}, 1);
+
+shouldBe(function() {
+ const x = {a: 1};
+ x["a"] ??= 42;
+ return x["a"];
+}, 1);
+
+shouldBe(function() {
+ const x = {a: ""};
+ return x["a"] ??= 42;
+}, "");
+
+shouldBe(function() {
+ const x = {a: ""};
+ x["a"] ??= 42;
+ return x["a"];
+}, "");
+
+shouldBe(function() {
+ const x = {a: "test"};
+ return x["a"] ??= 42;
+}, "test");
+
+shouldBe(function() {
+ const x = {a: "test"};
+ x["a"] ??= 42;
+ return x["a"];
+}, "test");
+
+shouldBe(function() {
+ const x = {a: {}};
+ return x["a"] ??= 42;
+}, Object);
+
+shouldBe(function() {
+ const x = {a: {}};
+ x["a"] ??= 42;
+ return x["a"];
+}, Object);
+
+shouldBe(function() {
+ const x = {a: []};
+ return x["a"] ??= 42;
+}, Array);
+
+shouldBe(function() {
+ const x = {a: []};
+ x["a"] ??= 42;
+ return x["a"];
+}, Array);
+
+
+
+shouldBe(function() {
+ let x = [];
+ return x[0] ??= 42;
+}, 42);
+
+shouldBe(function() {
+ let x = [];
+ x[0] ??= 42;
+ return x[0];
+}, 42);
+
+shouldBe(function() {
+ let x = [undefined];
+ return x[0] ??= 42;
+}, 42);
+
+shouldBe(function() {
+ let x = [undefined];
+ x[0] ??= 42;
+ return x[0];
+}, 42);
+
+shouldBe(function() {
+ let x = [null];
+ return x[0] ??= 42;
+}, 42);
+
+shouldBe(function() {
+ let x = [null];
+ x[0] ??= 42;
+ return x[0];
+}, 42);
+
+shouldBe(function() {
+ let x = [true];
+ return x[0] ??= 42;
+}, true);
+
+shouldBe(function() {
+ let x = [true];
+ x[0] ??= 42;
+ return x[0];
+}, true);
+
+shouldBe(function() {
+ let x = [false];
+ return x[0] ??= 42;
+}, false);
+
+shouldBe(function() {
+ let x = [false];
+ x[0] ??= 42;
+ return x[0];
+}, false);
+
+shouldBe(function() {
+ let x = [0];
+ return x[0] ??= 42;
+}, 0);
+
+shouldBe(function() {
+ let x = [0];
+ x[0] ??= 42;
+ return x[0];
+}, 0);
+
+shouldBe(function() {
+ let x = [1];
+ return x[0] ??= 42;
+}, 1);
+
+shouldBe(function() {
+ let x = [1];
+ x[0] ??= 42;
+ return x[0];
+}, 1);
+
+shouldBe(function() {
+ let x = [""];
+ return x[0] ??= 42;
+}, "");
+
+shouldBe(function() {
+ let x = [""];
+ x[0] ??= 42;
+ return x[0];
+}, "");
+
+shouldBe(function() {
+ let x = ["test"];
+ return x[0] ??= 42;
+}, "test");
+
+shouldBe(function() {
+ let x = ["test"];
+ x[0] ??= 42;
+ return x[0];
+}, "test");
+
+shouldBe(function() {
+ let x = [{}];
+ return x[0] ??= 42;
+}, Object);
+
+shouldBe(function() {
+ let x = [{}];
+ x[0] ??= 42;
+ return x[0];
+}, Object);
+
+shouldBe(function() {
+ let x = [[]];
+ return x[0] ??= 42;
+}, Array);
+
+shouldBe(function() {
+ let x = [[]];
+ x[0] ??= 42;
+ return x[0];
+}, Array);
+
+
+
+shouldBe(function() {
+ const x = [];
+ return x[0] ??= 42;
+}, 42);
+
+shouldBe(function() {
+ const x = [];
+ x[0] ??= 42;
+ return x[0];
+}, 42);
+
+shouldBe(function() {
+ const x = [undefined];
+ return x[0] ??= 42;
+}, 42);
+
+shouldBe(function() {
+ const x = [undefined];
+ x[0] ??= 42;
+ return x[0];
+}, 42);
+
+shouldBe(function() {
+ const x = [null];
+ return x[0] ??= 42;
+}, 42);
+
+shouldBe(function() {
+ const x = [null];
+ x[0] ??= 42;
+ return x[0];
+}, 42);
+
+shouldBe(function() {
+ const x = [true];
+ return x[0] ??= 42;
+}, true);
+
+shouldBe(function() {
+ const x = [true];
+ x[0] ??= 42;
+ return x[0];
+}, true);
+
+shouldBe(function() {
+ const x = [false];
+ return x[0] ??= 42;
+}, false);
+
+shouldBe(function() {
+ const x = [false];
+ x[0] ??= 42;
+ return x[0];
+}, false);
+
+shouldBe(function() {
+ const x = [0];
+ return x[0] ??= 42;
+}, 0);
+
+shouldBe(function() {
+ const x = [0];
+ x[0] ??= 42;
+ return x[0];
+}, 0);
+
+shouldBe(function() {
+ const x = [1];
+ return x[0] ??= 42;
+}, 1);
+
+shouldBe(function() {
+ const x = [1];
+ x[0] ??= 42;
+ return x[0];
+}, 1);
+
+shouldBe(function() {
+ const x = [""];
+ return x[0] ??= 42;
+}, "");
+
+shouldBe(function() {
+ const x = [""];
+ x[0] ??= 42;
+ return x[0];
+}, "");
+
+shouldBe(function() {
+ const x = ["test"];
+ return x[0] ??= 42;
+}, "test");
+
+shouldBe(function() {
+ const x = ["test"];
+ x[0] ??= 42;
+ return x[0];
+}, "test");
+
+shouldBe(function() {
+ const x = [{}];
+ return x[0] ??= 42;
+}, Object);
+
+shouldBe(function() {
+ const x = [{}];
+ x[0] ??= 42;
+ return x[0];
+}, Object);
+
+shouldBe(function() {
+ const x = [[]];
+ return x[0] ??= 42;
+}, Array);
+
+shouldBe(function() {
+ const x = [[]];
+ x[0] ??= 42;
+ return x[0];
+}, Array);
+
+
+
+shouldBe(function() {
+ let x = false;
+ let y = 1;
+ let z = 2;
+ return x ??= y + z;
+}, false);
+
+shouldBe(function() {
+ let x = false;
+ let y = 1;
+ let z = 2;
+ return x ??= y = z;
+}, false);
+
+shouldBe(function() {
+ let x = false;
+ let y = 1;
+ let z = 2;
+ return x ??= y && z;
+}, false);
+
+shouldBe(function() {
+ let x = false;
+ let y = 1;
+ let z = 2;
+ return x ??= y ?? z;
+}, false);
+
+shouldBe(function() {
+ let x = false;
+ let y = 1;
+ let z = 2;
+ return x ??= y || z;
+}, false);
+
+shouldBe(function() {
+ let x = false;
+ let y = 1;
+ let z = 2;
+ return x ??= y &&= z;
+}, false);
+
+shouldBe(function() {
+ let x = false;
+ let y = 1;
+ let z = 2;
+ return x ??= y ??= z;
+}, false);
+
+shouldBe(function() {
+ let x = false;
+ let y = 1;
+ let z = 2;
+ return x ??= y ||= z;
+}, false);
+
+
+
+shouldBe(function() {
+ let x = null;
+ let y = 1;
+ let z = 2;
+ return x ??= y + z;
+}, 3);
+
+shouldBe(function() {
+ let x = null;
+ let y = 1;
+ let z = 2;
+ return x ??= y = z;
+}, 2);
+
+shouldBe(function() {
+ let x = null;
+ let y = 1;
+ let z = 2;
+ return x ??= y && z;
+}, 2);
+
+shouldBe(function() {
+ let x = null;
+ let y = 1;
+ let z = 2;
+ return x ??= y ?? z;
+}, 1);
+
+shouldBe(function() {
+ let x = null;
+ let y = 1;
+ let z = 2;
+ return x ??= y || z;
+}, 1);
+
+shouldBe(function() {
+ let x = null;
+ let y = 1;
+ let z = 2;
+ return x ??= y &&= z;
+}, 2);
+
+shouldBe(function() {
+ let x = null;
+ let y = 1;
+ let z = 2;
+ return x ??= y ??= z;
+}, 1);
+
+shouldBe(function() {
+ let x = null;
+ let y = 1;
+ let z = 2;
+ return x ??= y ||= z;
+}, 1);
+
+
+
+shouldBe(function() {
+ let log = [];
+
+ let a = true;
+ let x = {
+ get a() {
+ log.push("get");
+ return a;
+ },
+ set a(v) {
+ log.push("set");
+ a = v;
+ },
+ };
+
+ x.a ??= 42;
+ x.a ??= 42;
+
+ return log.join(" ") + " " + a;
+}, "get get true");
+
+shouldBe(function() {
+ let log = [];
+
+ let a = false;
+ let x = {
+ get a() {
+ log.push("get");
+ return a;
+ },
+ set a(v) {
+ log.push("set");
+ a = v;
+ },
+ };
+
+ x.a ??= 42;
+ x.a ??= 42;
+
+ return log.join(" ") + " " + a;
+}, "get get false");
+
+shouldBe(function() {
+ let log = [];
+
+ let a = undefined;
+ let x = {
+ get a() {
+ log.push("get");
+ return a;
+ },
+ set a(v) {
+ log.push("set");
+ a = v;
+ },
+ };
+
+ x.a ??= 42;
+ x.a ??= 42;
+
+ return log.join(" ") + " " + a;
+}, "get set get 42");
+
+
+
+shouldBe(function() {
+ let log = [];
+
+ let a = true;
+ let x = {
+ get a() {
+ log.push("get");
+ return a;
+ },
+ set a(v) {
+ log.push("set");
+ a = v;
+ },
+ };
+
+ x["a"] ??= 42;
+ x["a"] ??= 42;
+
+ return log.join(" ") + " " + a;
+}, "get get true");
+
+shouldBe(function() {
+ let log = [];
+
+ let a = false;
+ let x = {
+ get a() {
+ log.push("get");
+ return a;
+ },
+ set a(v) {
+ log.push("set");
+ a = v;
+ },
+ };
+
+ x["a"] ??= 42;
+ x["a"] ??= 42;
+
+ return log.join(" ") + " " + a;
+}, "get get false");
+
+shouldBe(function() {
+ let log = [];
+
+ let a = undefined;
+ let x = {
+ get a() {
+ log.push("get");
+ return a;
+ },
+ set a(v) {
+ log.push("set");
+ a = v;
+ },
+ };
+
+ x["a"] ??= 42;
+ x["a"] ??= 42;
+
+ return log.join(" ") + " " + a;
+}, "get set get 42");
+
+
+
+shouldBe(function() {
+ let log = [];
+
+ class Parent {
+ get a() {
+ log.push("get-parent");
+ return this._a;
+ }
+ set a(v) {
+ log.push("set-parent");
+ this._a ??= v;
+ }
+ }
+ class Child extends Parent {
+ get a() {
+ log.push("get-child");
+ return super.a;
+ }
+ set a(v) {
+ log.push("set-child");
+ super.a ??= v;
+ }
+ }
+
+ let x = new Child;
+ x._a = true;
+ x.a ??= 42;
+ x.a ??= 42;
+
+ return log.join(" ") + " " + x._a;
+}, "get-child get-parent get-child get-parent true");
+
+shouldBe(function() {
+ let log = [];
+
+ class Parent {
+ get a() {
+ log.push("get-parent");
+ return this._a;
+ }
+ set a(v) {
+ log.push("set-parent");
+ this._a ??= v;
+ }
+ }
+ class Child extends Parent {
+ get a() {
+ log.push("get-child");
+ return super.a;
+ }
+ set a(v) {
+ log.push("set-child");
+ super.a ??= v;
+ }
+ }
+
+ let x = new Child;
+ x._a = false;
+ x.a ??= 42;
+ x.a ??= 42;
+
+ return log.join(" ") + " " + x._a;
+}, "get-child get-parent get-child get-parent false");
+
+shouldBe(function() {
+ let log = [];
+
+ class Parent {
+ get a() {
+ log.push("get-parent");
+ return this._a;
+ }
+ set a(v) {
+ log.push("set-parent");
+ this._a ??= v;
+ }
+ }
+ class Child extends Parent {
+ get a() {
+ log.push("get-child");
+ return super.a;
+ }
+ set a(v) {
+ log.push("set-child");
+ super.a ??= v;
+ }
+ }
+
+ let x = new Child;
+ x._a = undefined;
+ x.a ??= 42;
+ x.a ??= 42;
+
+ return log.join(" ") + " " + x._a;
+}, "get-child get-parent set-child get-parent set-parent get-child get-parent 42");
+
+
+
+shouldBe(function() {
+ let log = [];
+
+ class Parent {
+ get a() {
+ log.push("get-parent");
+ return this._a;
+ }
+ set a(v) {
+ log.push("set-parent");
+ this._a ??= v;
+ }
+ }
+ class Child extends Parent {
+ get a() {
+ log.push("get-child");
+ return super["a"];
+ }
+ set a(v) {
+ log.push("set-child");
+ super["a"] ??= v;
+ }
+ }
+
+ let x = new Child;
+ x._a = true;
+ x["a"] ??= 42;
+ x["a"] ??= 42;
+
+ return log.join(" ") + " " + x._a;
+}, "get-child get-parent get-child get-parent true");
+
+shouldBe(function() {
+ let log = [];
+
+ class Parent {
+ get a() {
+ log.push("get-parent");
+ return this._a;
+ }
+ set a(v) {
+ log.push("set-parent");
+ this._a ??= v;
+ }
+ }
+ class Child extends Parent {
+ get a() {
+ log.push("get-child");
+ return super["a"];
+ }
+ set a(v) {
+ log.push("set-child");
+ super["a"] ??= v;
+ }
+ }
+
+ let x = new Child;
+ x._a = false;
+ x["a"] ??= 42;
+ x["a"] ??= 42;
+
+ return log.join(" ") + " " + x._a;
+}, "get-child get-parent get-child get-parent false");
+
+shouldBe(function() {
+ let log = [];
+
+ class Parent {
+ get a() {
+ log.push("get-parent");
+ return this._a;
+ }
+ set a(v) {
+ log.push("set-parent");
+ this._a ??= v;
+ }
+ }
+ class Child extends Parent {
+ get a() {
+ log.push("get-child");
+ return super["a"];
+ }
+ set a(v) {
+ log.push("set-child");
+ super["a"] ??= v;
+ }
+ }
+
+ let x = new Child;
+ x._a = undefined;
+ x["a"] ??= 42;
+ x["a"] ??= 42;
+
+ return log.join(" ") + " " + x._a;
+}, "get-child get-parent set-child get-parent set-parent get-child get-parent 42");
+
+
+
+shouldBe(function() {
+ let x = {};
+ Object.defineProperty(x, "a", {
+ value: true,
+ writable: false,
+ });
+ return x.a ??= 42;
+}, true);
+
+shouldBe(function() {
+ let x = {};
+ Object.defineProperty(x, "a", {
+ value: false,
+ writable: false,
+ });
+ return x.a ??= 42;
+}, false);
+
+shouldBe(function() {
+ let x = {};
+ Object.defineProperty(x, "a", {
+ value: undefined,
+ writable: false,
+ });
+ return x.a ??= 42;
+}, 42);
+
+
+
+shouldBe(function() {
+ "use strict";
+ let x = {};
+ Object.defineProperty(x, "a", {
+ value: true,
+ writable: false,
+ });
+ return x.a ??= 42;
+}, true);
+
+shouldBe(function() {
+ "use strict";
+ let x = {};
+ Object.defineProperty(x, "a", {
+ value: false,
+ writable: false,
+ });
+ return x.a ??= 42;
+}, false);
+
+shouldThrow(function() {
+ "use strict";
+ let x = {};
+ Object.defineProperty(x, "a", {
+ value: undefined,
+ writable: false,
+ });
+ return x.a ??= 42;
+}, TypeError);
+
+
+
+shouldBe(function() {
+ let x = {};
+ Object.defineProperty(x, "a", {
+ value: true,
+ writable: false,
+ });
+ return x["a"] ??= 42;
+}, true);
+
+shouldBe(function() {
+ let x = {};
+ Object.defineProperty(x, "a", {
+ value: false,
+ writable: false,
+ });
+ return x["a"] ??= 42;
+}, false);
+
+shouldBe(function() {
+ let x = {};
+ Object.defineProperty(x, "a", {
+ value: undefined,
+ writable: false,
+ });
+ return x["a"] ??= 42;
+}, 42);
+
+
+
+shouldBe(function() {
+ "use strict";
+ let x = {};
+ Object.defineProperty(x, "a", {
+ value: true,
+ writable: false,
+ });
+ return x["a"] ??= 42;
+}, true);
+
+shouldBe(function() {
+ "use strict";
+ let x = {};
+ Object.defineProperty(x, "a", {
+ value: false,
+ writable: false,
+ });
+ return x["a"] ??= 42;
+}, false);
+
+shouldThrow(function() {
+ "use strict";
+ let x = {};
+ Object.defineProperty(x, "a", {
+ value: undefined,
+ writable: false,
+ });
+ return x["a"] ??= 42;
+}, TypeError);
+
+
+
+shouldBe(function() {
+ let x = true;
+ (function() {
+ x ??= 42;
+ })();
+ return x;
+}, true);
+
+shouldBe(function() {
+ let x = false;
+ return (function() {
+ return x ??= 42;
+ })();
+}, false);
+
+shouldBe(function() {
+ let x = undefined;
+ return (function() {
+ return x ??= 42;
+ })();
+}, 42);
+
+
+
+shouldBe(function() {
+ const x = true;
+ (function() {
+ x ??= 42;
+ })();
+ return x;
+}, true);
+
+shouldBe(function() {
+ const x = false;
+ return (function() {
+ return x ??= 42;
+ })();
+}, false);
+
+shouldThrow(function() {
+ const x = undefined;
+ return (function() {
+ return x ??= 42;
+ })();
+}, TypeError);
+
+
+
+shouldBe(function() {
+ let count = 0;
+
+ const x = true;
+ x ??= ++count;
+
+ return count;
+}, 0);
+
+shouldBe(function() {
+ let count = 0;
+
+ const x = false;
+ x ??= ++count;
+
+ return count;
+}, 0);
+
+shouldBe(function() {
+ let count = 0;
+
+ const x = undefined;
+ try {
+ x ??= ++count;
+ } catch { }
+
+ return count;
+}, 1);
+
+
+
+shouldBe(function() {
+ let count = 0;
+
+ const x = true;
+ function capture() { return x; }
+
+ x ??= ++count;
+
+ return count;
+}, 0);
+
+shouldBe(function() {
+ let count = 0;
+
+ const x = false;
+ function capture() { return x; }
+
+ x ??= ++count;
+
+ return count;
+}, 0);
+
+shouldBe(function() {
+ let count = 0;
+
+ const x = undefined;
+ function capture() { return x; }
+
+ try {
+ x ??= ++count;
+ } catch { }
+
+ return count;
+}, 1);
+
+
+
+shouldThrow(function() {
+ x ??= 42;
+ let x = true;
+ return x;
+}, ReferenceError);
+
+
+
+shouldBe(function() {
+ return undefined ??= 42;
+}, 42);
+
+shouldThrowSyntaxError(`null ??= 42`);
+
+shouldThrowSyntaxError(`true ??= 42`);
+
+shouldThrowSyntaxError(`false ??= 42`);
+
+shouldThrowSyntaxError(`0 ??= 42`);
+
+shouldThrowSyntaxError(`1 ??= 42`);
+
+shouldThrowSyntaxError(`"" ??= 42`);
+
+shouldThrowSyntaxError(`"test" ??= 42`);
+
+shouldThrowSyntaxError(`{} ??= 42`);
+
+shouldThrowSyntaxError(`[] ??= 42`);
Added: trunk/JSTests/stress/logical-assignment-operator-or.js (0 => 260119)
--- trunk/JSTests/stress/logical-assignment-operator-or.js (rev 0)
+++ trunk/JSTests/stress/logical-assignment-operator-or.js 2020-04-15 07:02:55 UTC (rev 260119)
@@ -0,0 +1,1685 @@
+//@ runLogicalAssignmentOperatorsEnabled
+
+function shouldBe(func, expected) {
+ let actual = func();
+ if (typeof expected === "function" ? !(actual instanceof expected) : actual !== expected)
+ throw new Error(`expected ${JSON.stringify(expected)} but got ${JSON.stringify(actual)}`);
+}
+
+function shouldThrow(func, errorType) {
+ let error;
+ try {
+ func();
+ } catch (e) {
+ error = e;
+ }
+
+ if (!(error instanceof errorType))
+ throw new Error(`Expected ${errorType.name} but saw ${error && error.name}!`);
+}
+
+function shouldThrowSyntaxError(script) {
+ let error;
+ try {
+ eval(script);
+ } catch (e) {
+ error = e;
+ }
+
+ if (!(error instanceof SyntaxError))
+ throw new Error(`Expected SyntaxError but saw ${error && error.name}!`);
+}
+
+shouldBe(function() {
+ let x;
+ return x ||= 42;
+}, 42);
+
+shouldBe(function() {
+ let x;
+ x ||= 42;
+ return x;
+}, 42);
+
+shouldBe(function() {
+ let x = undefined;
+ return x ||= 42;
+}, 42);
+
+shouldBe(function() {
+ let x = undefined;
+ x ||= 42;
+ return x;
+}, 42);
+
+shouldBe(function() {
+ let x = null;
+ return x ||= 42;
+}, 42);
+
+shouldBe(function() {
+ let x = null;
+ x ||= 42;
+ return x;
+}, 42);
+
+shouldBe(function() {
+ let x = true;
+ return x ||= 42;
+}, true);
+
+shouldBe(function() {
+ let x = true;
+ x ||= 42;
+ return x;
+}, true);
+
+shouldBe(function() {
+ let x = false;
+ return x ||= 42;
+}, 42);
+
+shouldBe(function() {
+ let x = false;
+ x ||= 42;
+ return x;
+}, 42);
+
+shouldBe(function() {
+ let x = 0;
+ return x ||= 42;
+}, 42);
+
+shouldBe(function() {
+ let x = 0;
+ x ||= 42;
+ return x;
+}, 42);
+
+shouldBe(function() {
+ let x = 1;
+ return x ||= 42;
+}, 1);
+
+shouldBe(function() {
+ let x = 1;
+ x ||= 42;
+ return x;
+}, 1);
+
+shouldBe(function() {
+ let x = "";
+ return x ||= 42;
+}, 42);
+
+shouldBe(function() {
+ let x = "";
+ x ||= 42;
+ return x;
+}, 42);
+
+shouldBe(function() {
+ let x = "test";
+ return x ||= 42;
+}, "test");
+
+shouldBe(function() {
+ let x = "test";
+ x ||= 42;
+ return x;
+}, "test");
+
+shouldBe(function() {
+ let x = {};
+ return x ||= 42;
+}, Object);
+
+shouldBe(function() {
+ let x = {};
+ x ||= 42;
+ return x;
+}, Object);
+
+shouldBe(function() {
+ let x = [];
+ return x ||= 42;
+}, Array);
+
+shouldBe(function() {
+ let x = [];
+ x ||= 42;
+ return x;
+}, Array);
+
+
+
+shouldThrow(function() {
+ const x = undefined;
+ return x ||= 42;
+}, TypeError);
+
+shouldThrow(function() {
+ const x = null;
+ return x ||= 42;
+}, TypeError);
+
+shouldBe(function() {
+ const x = true;
+ return x ||= 42;
+}, true);
+
+shouldBe(function() {
+ const x = true;
+ x ||= 42;
+ return x;
+}, true);
+
+shouldThrow(function() {
+ const x = false;
+ return x ||= 42;
+}, TypeError);
+
+shouldThrow(function() {
+ const x = 0;
+ return x ||= 42;
+}, TypeError);
+
+shouldBe(function() {
+ const x = 1;
+ return x ||= 42;
+}, 1);
+
+shouldBe(function() {
+ const x = 1;
+ x ||= 42;
+ return x;
+}, 1);
+
+shouldThrow(function() {
+ const x = "";
+ return x ||= 42;
+}, TypeError);
+
+shouldBe(function() {
+ const x = "test";
+ return x ||= 42;
+}, "test");
+
+shouldBe(function() {
+ const x = "test";
+ return x ||= 42;
+}, "test");
+
+shouldBe(function() {
+ const x = {};
+ return x ||= 42;
+}, Object);
+
+shouldBe(function() {
+ const x = {};
+ return x ||= 42;
+}, Object);
+
+shouldBe(function() {
+ const x = [];
+ return x ||= 42;
+}, Array);
+
+shouldBe(function() {
+ const x = [];
+ return x ||= 42;
+}, Array);
+
+
+
+shouldBe(function() {
+ let x = {};
+ return x.a ||= 42;
+}, 42);
+
+shouldBe(function() {
+ let x = {};
+ x.a ||= 42;
+ return x.a;
+}, 42);
+
+shouldBe(function() {
+ let x = {a: undefined};
+ return x.a ||= 42;
+}, 42);
+
+shouldBe(function() {
+ let x = {a: undefined};
+ x.a ||= 42;
+ return x.a;
+}, 42);
+
+shouldBe(function() {
+ let x = {a: null};
+ return x.a ||= 42;
+}, 42);
+
+shouldBe(function() {
+ let x = {a: null};
+ x.a ||= 42;
+ return x.a;
+}, 42);
+
+shouldBe(function() {
+ let x = {a: true};
+ return x.a ||= 42;
+}, true);
+
+shouldBe(function() {
+ let x = {a: true};
+ x.a ||= 42;
+ return x.a;
+}, true);
+
+shouldBe(function() {
+ let x = {a: false};
+ return x.a ||= 42;
+}, 42);
+
+shouldBe(function() {
+ let x = {a: false};
+ x.a ||= 42;
+ return x.a;
+}, 42);
+
+shouldBe(function() {
+ let x = {a: 0};
+ return x.a ||= 42;
+}, 42);
+
+shouldBe(function() {
+ let x = {a: 0};
+ x.a ||= 42;
+ return x.a;
+}, 42);
+
+shouldBe(function() {
+ let x = {a: 1};
+ return x.a ||= 42;
+}, 1);
+
+shouldBe(function() {
+ let x = {a: 1};
+ x.a ||= 42;
+ return x.a;
+}, 1);
+
+shouldBe(function() {
+ let x = {a: ""};
+ return x.a ||= 42;
+}, 42);
+
+shouldBe(function() {
+ let x = {a: ""};
+ x.a ||= 42;
+ return x.a;
+}, 42);
+
+shouldBe(function() {
+ let x = {a: "test"};
+ return x.a ||= 42;
+}, "test");
+
+shouldBe(function() {
+ let x = {a: "test"};
+ x.a ||= 42;
+ return x.a;
+}, "test");
+
+shouldBe(function() {
+ let x = {a: {}};
+ return x.a ||= 42;
+}, Object);
+
+shouldBe(function() {
+ let x = {a: {}};
+ x.a ||= 42;
+ return x.a;
+}, Object);
+
+shouldBe(function() {
+ let x = {a: []};
+ return x.a ||= 42;
+}, Array);
+
+shouldBe(function() {
+ let x = {a: []};
+ x.a ||= 42;
+ return x.a;
+}, Array);
+
+
+
+shouldBe(function() {
+ const x = {};
+ return x.a ||= 42;
+}, 42);
+
+shouldBe(function() {
+ const x = {};
+ x.a ||= 42;
+ return x.a;
+}, 42);
+
+shouldBe(function() {
+ const x = {a: undefined};
+ return x.a ||= 42;
+}, 42);
+
+shouldBe(function() {
+ const x = {a: undefined};
+ x.a ||= 42;
+ return x.a;
+}, 42);
+
+shouldBe(function() {
+ const x = {a: null};
+ return x.a ||= 42;
+}, 42);
+
+shouldBe(function() {
+ const x = {a: null};
+ x.a ||= 42;
+ return x.a;
+}, 42);
+
+shouldBe(function() {
+ const x = {a: true};
+ return x.a ||= 42;
+}, true);
+
+shouldBe(function() {
+ const x = {a: true};
+ x.a ||= 42;
+ return x.a;
+}, true);
+
+shouldBe(function() {
+ const x = {a: false};
+ return x.a ||= 42;
+}, 42);
+
+shouldBe(function() {
+ const x = {a: false};
+ x.a ||= 42;
+ return x.a;
+}, 42);
+
+shouldBe(function() {
+ const x = {a: 0};
+ return x.a ||= 42;
+}, 42);
+
+shouldBe(function() {
+ const x = {a: 0};
+ x.a ||= 42;
+ return x.a;
+}, 42);
+
+shouldBe(function() {
+ const x = {a: 1};
+ return x.a ||= 42;
+}, 1);
+
+shouldBe(function() {
+ const x = {a: 1};
+ x.a ||= 42;
+ return x.a;
+}, 1);
+
+shouldBe(function() {
+ const x = {a: ""};
+ return x.a ||= 42;
+}, 42);
+
+shouldBe(function() {
+ const x = {a: ""};
+ x.a ||= 42;
+ return x.a;
+}, 42);
+
+shouldBe(function() {
+ const x = {a: "test"};
+ return x.a ||= 42;
+}, "test");
+
+shouldBe(function() {
+ const x = {a: "test"};
+ x.a ||= 42;
+ return x.a;
+}, "test");
+
+shouldBe(function() {
+ const x = {a: {}};
+ return x.a ||= 42;
+}, Object);
+
+shouldBe(function() {
+ const x = {a: {}};
+ x.a ||= 42;
+ return x.a;
+}, Object);
+
+shouldBe(function() {
+ const x = {a: []};
+ return x.a ||= 42;
+}, Array);
+
+shouldBe(function() {
+ const x = {a: []};
+ x.a ||= 42;
+ return x.a;
+}, Array);
+
+
+
+shouldBe(function() {
+ let x = {};
+ return x["a"] ||= 42;
+}, 42);
+
+shouldBe(function() {
+ let x = {};
+ x["a"] ||= 42;
+ return x["a"];
+}, 42);
+
+shouldBe(function() {
+ let x = {a: undefined};
+ return x["a"] ||= 42;
+}, 42);
+
+shouldBe(function() {
+ let x = {a: undefined};
+ x["a"] ||= 42;
+ return x["a"];
+}, 42);
+
+shouldBe(function() {
+ let x = {a: null};
+ return x["a"] ||= 42;
+}, 42);
+
+shouldBe(function() {
+ let x = {a: null};
+ x["a"] ||= 42;
+ return x["a"];
+}, 42);
+
+shouldBe(function() {
+ let x = {a: true};
+ return x["a"] ||= 42;
+}, true);
+
+shouldBe(function() {
+ let x = {a: true};
+ x["a"] ||= 42;
+ return x["a"];
+}, true);
+
+shouldBe(function() {
+ let x = {a: false};
+ return x["a"] ||= 42;
+}, 42);
+
+shouldBe(function() {
+ let x = {a: false};
+ x["a"] ||= 42;
+ return x["a"];
+}, 42);
+
+shouldBe(function() {
+ let x = {a: 0};
+ return x["a"] ||= 42;
+}, 42);
+
+shouldBe(function() {
+ let x = {a: 0};
+ x["a"] ||= 42;
+ return x["a"];
+}, 42);
+
+shouldBe(function() {
+ let x = {a: 1};
+ return x["a"] ||= 42;
+}, 1);
+
+shouldBe(function() {
+ let x = {a: 1};
+ x["a"] ||= 42;
+ return x["a"];
+}, 1);
+
+shouldBe(function() {
+ let x = {a: ""};
+ return x["a"] ||= 42;
+}, 42);
+
+shouldBe(function() {
+ let x = {a: ""};
+ x["a"] ||= 42;
+ return x["a"];
+}, 42);
+
+shouldBe(function() {
+ let x = {a: "test"};
+ return x["a"] ||= 42;
+}, "test");
+
+shouldBe(function() {
+ let x = {a: "test"};
+ x["a"] ||= 42;
+ return x["a"];
+}, "test");
+
+shouldBe(function() {
+ let x = {a: {}};
+ return x["a"] ||= 42;
+}, Object);
+
+shouldBe(function() {
+ let x = {a: {}};
+ x["a"] ||= 42;
+ return x["a"];
+}, Object);
+
+shouldBe(function() {
+ let x = {a: []};
+ return x["a"] ||= 42;
+}, Array);
+
+shouldBe(function() {
+ let x = {a: []};
+ x["a"] ||= 42;
+ return x["a"];
+}, Array);
+
+
+
+shouldBe(function() {
+ const x = {};
+ return x["a"] ||= 42;
+}, 42);
+
+shouldBe(function() {
+ const x = {};
+ x["a"] ||= 42;
+ return x["a"];
+}, 42);
+
+shouldBe(function() {
+ const x = {a: undefined};
+ return x["a"] ||= 42;
+}, 42);
+
+shouldBe(function() {
+ const x = {a: undefined};
+ x["a"] ||= 42;
+ return x["a"];
+}, 42);
+
+shouldBe(function() {
+ const x = {a: null};
+ return x["a"] ||= 42;
+}, 42);
+
+shouldBe(function() {
+ const x = {a: null};
+ x["a"] ||= 42;
+ return x["a"];
+}, 42);
+
+shouldBe(function() {
+ const x = {a: true};
+ return x["a"] ||= 42;
+}, true);
+
+shouldBe(function() {
+ const x = {a: true};
+ x["a"] ||= 42;
+ return x["a"];
+}, true);
+
+shouldBe(function() {
+ const x = {a: false};
+ return x["a"] ||= 42;
+}, 42);
+
+shouldBe(function() {
+ const x = {a: false};
+ x["a"] ||= 42;
+ return x["a"];
+}, 42);
+
+shouldBe(function() {
+ const x = {a: 0};
+ return x["a"] ||= 42;
+}, 42);
+
+shouldBe(function() {
+ const x = {a: 0};
+ x["a"] ||= 42;
+ return x["a"];
+}, 42);
+
+shouldBe(function() {
+ const x = {a: 1};
+ return x["a"] ||= 42;
+}, 1);
+
+shouldBe(function() {
+ const x = {a: 1};
+ x["a"] ||= 42;
+ return x["a"];
+}, 1);
+
+shouldBe(function() {
+ const x = {a: ""};
+ return x["a"] ||= 42;
+}, 42);
+
+shouldBe(function() {
+ const x = {a: ""};
+ x["a"] ||= 42;
+ return x["a"];
+}, 42);
+
+shouldBe(function() {
+ const x = {a: "test"};
+ return x["a"] ||= 42;
+}, "test");
+
+shouldBe(function() {
+ const x = {a: "test"};
+ x["a"] ||= 42;
+ return x["a"];
+}, "test");
+
+shouldBe(function() {
+ const x = {a: {}};
+ return x["a"] ||= 42;
+}, Object);
+
+shouldBe(function() {
+ const x = {a: {}};
+ x["a"] ||= 42;
+ return x["a"];
+}, Object);
+
+shouldBe(function() {
+ const x = {a: []};
+ return x["a"] ||= 42;
+}, Array);
+
+shouldBe(function() {
+ const x = {a: []};
+ x["a"] ||= 42;
+ return x["a"];
+}, Array);
+
+
+
+shouldBe(function() {
+ let x = [];
+ return x[0] ||= 42;
+}, 42);
+
+shouldBe(function() {
+ let x = [];
+ x[0] ||= 42;
+ return x[0];
+}, 42);
+
+shouldBe(function() {
+ let x = [undefined];
+ return x[0] ||= 42;
+}, 42);
+
+shouldBe(function() {
+ let x = [undefined];
+ x[0] ||= 42;
+ return x[0];
+}, 42);
+
+shouldBe(function() {
+ let x = [null];
+ return x[0] ||= 42;
+}, 42);
+
+shouldBe(function() {
+ let x = [null];
+ x[0] ||= 42;
+ return x[0];
+}, 42);
+
+shouldBe(function() {
+ let x = [true];
+ return x[0] ||= 42;
+}, true);
+
+shouldBe(function() {
+ let x = [true];
+ x[0] ||= 42;
+ return x[0];
+}, true);
+
+shouldBe(function() {
+ let x = [false];
+ return x[0] ||= 42;
+}, 42);
+
+shouldBe(function() {
+ let x = [false];
+ x[0] ||= 42;
+ return x[0];
+}, 42);
+
+shouldBe(function() {
+ let x = [0];
+ return x[0] ||= 42;
+}, 42);
+
+shouldBe(function() {
+ let x = [0];
+ x[0] ||= 42;
+ return x[0];
+}, 42);
+
+shouldBe(function() {
+ let x = [1];
+ return x[0] ||= 42;
+}, 1);
+
+shouldBe(function() {
+ let x = [1];
+ x[0] ||= 42;
+ return x[0];
+}, 1);
+
+shouldBe(function() {
+ let x = [""];
+ return x[0] ||= 42;
+}, 42);
+
+shouldBe(function() {
+ let x = [""];
+ x[0] ||= 42;
+ return x[0];
+}, 42);
+
+shouldBe(function() {
+ let x = ["test"];
+ return x[0] ||= 42;
+}, "test");
+
+shouldBe(function() {
+ let x = ["test"];
+ x[0] ||= 42;
+ return x[0];
+}, "test");
+
+shouldBe(function() {
+ let x = [{}];
+ return x[0] ||= 42;
+}, Object);
+
+shouldBe(function() {
+ let x = [{}];
+ x[0] ||= 42;
+ return x[0];
+}, Object);
+
+shouldBe(function() {
+ let x = [[]];
+ return x[0] ||= 42;
+}, Array);
+
+shouldBe(function() {
+ let x = [[]];
+ x[0] ||= 42;
+ return x[0];
+}, Array);
+
+
+
+shouldBe(function() {
+ const x = [];
+ return x[0] ||= 42;
+}, 42);
+
+shouldBe(function() {
+ const x = [];
+ x[0] ||= 42;
+ return x[0];
+}, 42);
+
+shouldBe(function() {
+ const x = [undefined];
+ return x[0] ||= 42;
+}, 42);
+
+shouldBe(function() {
+ const x = [undefined];
+ x[0] ||= 42;
+ return x[0];
+}, 42);
+
+shouldBe(function() {
+ const x = [null];
+ return x[0] ||= 42;
+}, 42);
+
+shouldBe(function() {
+ const x = [null];
+ x[0] ||= 42;
+ return x[0];
+}, 42);
+
+shouldBe(function() {
+ const x = [true];
+ return x[0] ||= 42;
+}, true);
+
+shouldBe(function() {
+ const x = [true];
+ x[0] ||= 42;
+ return x[0];
+}, true);
+
+shouldBe(function() {
+ const x = [false];
+ return x[0] ||= 42;
+}, 42);
+
+shouldBe(function() {
+ const x = [false];
+ x[0] ||= 42;
+ return x[0];
+}, 42);
+
+shouldBe(function() {
+ const x = [0];
+ return x[0] ||= 42;
+}, 42);
+
+shouldBe(function() {
+ const x = [0];
+ x[0] ||= 42;
+ return x[0];
+}, 42);
+
+shouldBe(function() {
+ const x = [1];
+ return x[0] ||= 42;
+}, 1);
+
+shouldBe(function() {
+ const x = [1];
+ x[0] ||= 42;
+ return x[0];
+}, 1);
+
+shouldBe(function() {
+ const x = [""];
+ return x[0] ||= 42;
+}, 42);
+
+shouldBe(function() {
+ const x = [""];
+ x[0] ||= 42;
+ return x[0];
+}, 42);
+
+shouldBe(function() {
+ const x = ["test"];
+ return x[0] ||= 42;
+}, "test");
+
+shouldBe(function() {
+ const x = ["test"];
+ x[0] ||= 42;
+ return x[0];
+}, "test");
+
+shouldBe(function() {
+ const x = [{}];
+ return x[0] ||= 42;
+}, Object);
+
+shouldBe(function() {
+ const x = [{}];
+ x[0] ||= 42;
+ return x[0];
+}, Object);
+
+shouldBe(function() {
+ const x = [[]];
+ return x[0] ||= 42;
+}, Array);
+
+shouldBe(function() {
+ const x = [[]];
+ x[0] ||= 42;
+ return x[0];
+}, Array);
+
+
+
+shouldBe(function() {
+ let x = true;
+ let y = 1;
+ let z = 2;
+ return x ||= y + z;
+}, true);
+
+shouldBe(function() {
+ let x = true;
+ let y = 1;
+ let z = 2;
+ return x ||= y = z;
+}, true);
+
+shouldBe(function() {
+ let x = true;
+ let y = 1;
+ let z = 2;
+ return x ||= y && z;
+}, true);
+
+shouldBe(function() {
+ let x = true;
+ let y = 1;
+ let z = 2;
+ return x ||= y ?? z;
+}, true);
+
+shouldBe(function() {
+ let x = true;
+ let y = 1;
+ let z = 2;
+ return x ||= y || z;
+}, true);
+
+shouldBe(function() {
+ let x = true;
+ let y = 1;
+ let z = 2;
+ return x ||= y &&= z;
+}, true);
+
+shouldBe(function() {
+ let x = true;
+ let y = 1;
+ let z = 2;
+ return x ||= y ||= z;
+}, true);
+
+shouldBe(function() {
+ let x = true;
+ let y = 1;
+ let z = 2;
+ return x ||= y ??= z;
+}, true);
+
+
+
+shouldBe(function() {
+ let x = null;
+ let y = 1;
+ let z = 2;
+ return x ||= y + z;
+}, 3);
+
+shouldBe(function() {
+ let x = null;
+ let y = 1;
+ let z = 2;
+ return x ||= y = z;
+}, 2);
+
+shouldBe(function() {
+ let x = null;
+ let y = 1;
+ let z = 2;
+ return x ||= y && z;
+}, 2);
+
+shouldBe(function() {
+ let x = null;
+ let y = 1;
+ let z = 2;
+ return x ||= y ?? z;
+}, 1);
+
+shouldBe(function() {
+ let x = null;
+ let y = 1;
+ let z = 2;
+ return x ||= y || z;
+}, 1);
+
+shouldBe(function() {
+ let x = null;
+ let y = 1;
+ let z = 2;
+ return x ||= y &&= z;
+}, 2);
+
+shouldBe(function() {
+ let x = null;
+ let y = 1;
+ let z = 2;
+ return x ||= y ||= z;
+}, 1);
+
+shouldBe(function() {
+ let x = null;
+ let y = 1;
+ let z = 2;
+ return x ||= y ??= z;
+}, 1);
+
+
+
+shouldBe(function() {
+ let log = [];
+
+ let a = true;
+ let x = {
+ get a() {
+ log.push("get");
+ return a;
+ },
+ set a(v) {
+ log.push("set");
+ a = v;
+ },
+ };
+
+ x.a ||= 42;
+ x.a ||= 42;
+
+ return log.join(" ") + " " + a;
+}, "get get true");
+
+shouldBe(function() {
+ let log = [];
+
+ let a = false;
+ let x = {
+ get a() {
+ log.push("get");
+ return a;
+ },
+ set a(v) {
+ log.push("set");
+ a = v;
+ },
+ };
+
+ x.a ||= 42;
+ x.a ||= 42;
+
+ return log.join(" ") + " " + a;
+}, "get set get 42");
+
+shouldBe(function() {
+ let log = [];
+
+ let a = undefined;
+ let x = {
+ get a() {
+ log.push("get");
+ return a;
+ },
+ set a(v) {
+ log.push("set");
+ a = v;
+ },
+ };
+
+ x.a ||= 42;
+ x.a ||= 42;
+
+ return log.join(" ") + " " + a;
+}, "get set get 42");
+
+
+
+shouldBe(function() {
+ let log = [];
+
+ let a = true;
+ let x = {
+ get a() {
+ log.push("get");
+ return a;
+ },
+ set a(v) {
+ log.push("set");
+ a = v;
+ },
+ };
+
+ x["a"] ||= 42;
+ x["a"] ||= 42;
+
+ return log.join(" ") + " " + a;
+}, "get get true");
+
+shouldBe(function() {
+ let log = [];
+
+ let a = false;
+ let x = {
+ get a() {
+ log.push("get");
+ return a;
+ },
+ set a(v) {
+ log.push("set");
+ a = v;
+ },
+ };
+
+ x["a"] ||= 42;
+ x["a"] ||= 42;
+
+ return log.join(" ") + " " + a;
+}, "get set get 42");
+
+shouldBe(function() {
+ let log = [];
+
+ let a = undefined;
+ let x = {
+ get a() {
+ log.push("get");
+ return a;
+ },
+ set a(v) {
+ log.push("set");
+ a = v;
+ },
+ };
+
+ x["a"] ||= 42;
+ x["a"] ||= 42;
+
+ return log.join(" ") + " " + a;
+}, "get set get 42");
+
+
+
+shouldBe(function() {
+ let log = [];
+
+ class Parent {
+ get a() {
+ log.push("get-parent");
+ return this._a;
+ }
+ set a(v) {
+ log.push("set-parent");
+ this._a ||= v;
+ }
+ }
+ class Child extends Parent {
+ get a() {
+ log.push("get-child");
+ return super.a;
+ }
+ set a(v) {
+ log.push("set-child");
+ super.a ||= v;
+ }
+ }
+
+ let x = new Child;
+ x._a = true;
+ x.a ||= 42;
+ x.a ||= 42;
+
+ return log.join(" ") + " " + x._a;
+}, "get-child get-parent get-child get-parent true");
+
+shouldBe(function() {
+ let log = [];
+
+ class Parent {
+ get a() {
+ log.push("get-parent");
+ return this._a;
+ }
+ set a(v) {
+ log.push("set-parent");
+ this._a ||= v;
+ }
+ }
+ class Child extends Parent {
+ get a() {
+ log.push("get-child");
+ return super.a;
+ }
+ set a(v) {
+ log.push("set-child");
+ super.a ||= v;
+ }
+ }
+
+ let x = new Child;
+ x._a = false;
+ x.a ||= 42;
+ x.a ||= 42;
+
+ return log.join(" ") + " " + x._a;
+}, "get-child get-parent set-child get-parent set-parent get-child get-parent 42");
+
+shouldBe(function() {
+ let log = [];
+
+ class Parent {
+ get a() {
+ log.push("get-parent");
+ return this._a;
+ }
+ set a(v) {
+ log.push("set-parent");
+ this._a ||= v;
+ }
+ }
+ class Child extends Parent {
+ get a() {
+ log.push("get-child");
+ return super.a;
+ }
+ set a(v) {
+ log.push("set-child");
+ super.a ||= v;
+ }
+ }
+
+ let x = new Child;
+ x._a = undefined;
+ x.a ||= 42;
+ x.a ||= 42;
+
+ return log.join(" ") + " " + x._a;
+}, "get-child get-parent set-child get-parent set-parent get-child get-parent 42");
+
+
+
+shouldBe(function() {
+ let log = [];
+
+ class Parent {
+ get a() {
+ log.push("get-parent");
+ return this._a;
+ }
+ set a(v) {
+ log.push("set-parent");
+ this._a ||= v;
+ }
+ }
+ class Child extends Parent {
+ get a() {
+ log.push("get-child");
+ return super["a"];
+ }
+ set a(v) {
+ log.push("set-child");
+ super["a"] ||= v;
+ }
+ }
+
+ let x = new Child;
+ x._a = true;
+ x["a"] ||= 42;
+ x["a"] ||= 42;
+
+ return log.join(" ") + " " + x._a;
+}, "get-child get-parent get-child get-parent true");
+
+shouldBe(function() {
+ let log = [];
+
+ class Parent {
+ get a() {
+ log.push("get-parent");
+ return this._a;
+ }
+ set a(v) {
+ log.push("set-parent");
+ this._a ||= v;
+ }
+ }
+ class Child extends Parent {
+ get a() {
+ log.push("get-child");
+ return super["a"];
+ }
+ set a(v) {
+ log.push("set-child");
+ super["a"] ||= v;
+ }
+ }
+
+ let x = new Child;
+ x._a = false;
+ x["a"] ||= 42;
+ x["a"] ||= 42;
+
+ return log.join(" ") + " " + x._a;
+}, "get-child get-parent set-child get-parent set-parent get-child get-parent 42");
+
+shouldBe(function() {
+ let log = [];
+
+ class Parent {
+ get a() {
+ log.push("get-parent");
+ return this._a;
+ }
+ set a(v) {
+ log.push("set-parent");
+ this._a ||= v;
+ }
+ }
+ class Child extends Parent {
+ get a() {
+ log.push("get-child");
+ return super["a"];
+ }
+ set a(v) {
+ log.push("set-child");
+ super["a"] ||= v;
+ }
+ }
+
+ let x = new Child;
+ x._a = undefined;
+ x["a"] ||= 42;
+ x["a"] ||= 42;
+
+ return log.join(" ") + " " + x._a;
+}, "get-child get-parent set-child get-parent set-parent get-child get-parent 42");
+
+
+
+shouldBe(function() {
+ let x = {};
+ Object.defineProperty(x, "a", {
+ value: true,
+ writable: false,
+ });
+ return x.a ||= 42;
+}, true);
+
+shouldBe(function() {
+ let x = {};
+ Object.defineProperty(x, "a", {
+ value: false,
+ writable: false,
+ });
+ return x.a ||= 42;
+}, 42);
+
+shouldBe(function() {
+ let x = {};
+ Object.defineProperty(x, "a", {
+ value: undefined,
+ writable: false,
+ });
+ return x.a ||= 42;
+}, 42);
+
+
+
+shouldBe(function() {
+ "use strict";
+ let x = {};
+ Object.defineProperty(x, "a", {
+ value: true,
+ writable: false,
+ });
+ return x.a ||= 42;
+}, true);
+
+shouldThrow(function() {
+ "use strict";
+ let x = {};
+ Object.defineProperty(x, "a", {
+ value: false,
+ writable: false,
+ });
+ return x.a ||= 42;
+}, TypeError);
+
+shouldThrow(function() {
+ "use strict";
+ let x = {};
+ Object.defineProperty(x, "a", {
+ value: undefined,
+ writable: false,
+ });
+ return x.a ||= 42;
+}, TypeError);
+
+
+
+shouldBe(function() {
+ let x = {};
+ Object.defineProperty(x, "a", {
+ value: true,
+ writable: false,
+ });
+ return x["a"] ||= 42;
+}, true);
+
+shouldBe(function() {
+ let x = {};
+ Object.defineProperty(x, "a", {
+ value: false,
+ writable: false,
+ });
+ return x["a"] ||= 42;
+}, 42);
+
+shouldBe(function() {
+ let x = {};
+ Object.defineProperty(x, "a", {
+ value: undefined,
+ writable: false,
+ });
+ return x["a"] ||= 42;
+}, 42);
+
+
+
+shouldBe(function() {
+ "use strict";
+ let x = {};
+ Object.defineProperty(x, "a", {
+ value: true,
+ writable: false,
+ });
+ return x["a"] ||= 42;
+}, true);
+
+shouldThrow(function() {
+ "use strict";
+ let x = {};
+ Object.defineProperty(x, "a", {
+ value: false,
+ writable: false,
+ });
+ return x["a"] ||= 42;
+}, TypeError);
+
+shouldThrow(function() {
+ "use strict";
+ let x = {};
+ Object.defineProperty(x, "a", {
+ value: undefined,
+ writable: false,
+ });
+ return x["a"] ||= 42;
+}, TypeError);
+
+
+
+shouldBe(function() {
+ let x = true;
+ (function() {
+ x ||= 42;
+ })();
+ return x;
+}, true);
+
+shouldBe(function() {
+ let x = false;
+ return (function() {
+ return x ||= 42;
+ })();
+}, 42);
+
+shouldBe(function() {
+ let x = undefined;
+ return (function() {
+ return x ||= 42;
+ })();
+}, 42);
+
+
+
+shouldBe(function() {
+ const x = true;
+ (function() {
+ x ||= 42;
+ })();
+ return x;
+}, true);
+
+shouldThrow(function() {
+ const x = false;
+ return (function() {
+ return x ||= 42;
+ })();
+}, TypeError);
+
+shouldThrow(function() {
+ const x = undefined;
+ return (function() {
+ return x ||= 42;
+ })();
+}, TypeError);
+
+
+
+shouldBe(function() {
+ let count = 0;
+
+ const x = true;
+ x ||= ++count;
+
+ return count;
+}, 0);
+
+shouldBe(function() {
+ let count = 0;
+
+ const x = false;
+ try {
+ x ||= ++count;
+ } catch { }
+
+ return count;
+}, 1);
+
+shouldBe(function() {
+ let count = 0;
+
+ const x = undefined;
+ try {
+ x ||= ++count;
+ } catch { }
+
+ return count;
+}, 1);
+
+
+
+shouldBe(function() {
+ let count = 0;
+
+ const x = true;
+ function capture() { return x; }
+
+ x ||= ++count;
+
+ return count;
+}, 0);
+
+shouldBe(function() {
+ let count = 0;
+
+ const x = false;
+ function capture() { return x; }
+
+ try {
+ x ||= ++count;
+ } catch { }
+
+ return count;
+}, 1);
+
+shouldBe(function() {
+ let count = 0;
+
+ const x = undefined;
+ function capture() { return x; }
+
+ try {
+ x ||= ++count;
+ } catch { }
+
+ return count;
+}, 1);
+
+
+
+shouldThrow(function() {
+ x ||= 42;
+ let x = true;
+ return x;
+}, ReferenceError);
+
+
+
+shouldBe(function() {
+ return undefined ||= 42;
+}, 42);
+
+shouldThrowSyntaxError(`null ||= 42`);
+
+shouldThrowSyntaxError(`true ||= 42`);
+
+shouldThrowSyntaxError(`false ||= 42`);
+
+shouldThrowSyntaxError(`0 ||= 42`);
+
+shouldThrowSyntaxError(`1 ||= 42`);
+
+shouldThrowSyntaxError(`"" ||= 42`);
+
+shouldThrowSyntaxError(`"test" ||= 42`);
+
+shouldThrowSyntaxError(`{} ||= 42`);
+
+shouldThrowSyntaxError(`[] ||= 42`);
Modified: trunk/JSTests/test262/config.yaml (260118 => 260119)
--- trunk/JSTests/test262/config.yaml 2020-04-15 06:20:39 UTC (rev 260118)
+++ trunk/JSTests/test262/config.yaml 2020-04-15 07:02:55 UTC (rev 260119)
@@ -4,6 +4,7 @@
BigInt: useBigInt
WeakRef: useWeakRefs
class-fields-public: usePublicClassFields
+ logical-assignment-operators: useLogicalAssignmentOperators
skip:
features:
- SharedArrayBuffer
@@ -20,8 +21,6 @@
# https://bugs.webkit.org/show_bug.cgi?id=202475
- regexp-match-indices
- top-level-await
- # https://bugs.webkit.org/show_bug.cgi?id=209716
- - logical-assignment-operators
# https://bugs.webkit.org/show_bug.cgi?id=202566
- Promise.any
- AggregateError
Modified: trunk/JSTests/test262/expectations.yaml (260118 => 260119)
--- trunk/JSTests/test262/expectations.yaml 2020-04-15 06:20:39 UTC (rev 260118)
+++ trunk/JSTests/test262/expectations.yaml 2020-04-15 07:02:55 UTC (rev 260119)
@@ -2718,6 +2718,12 @@
test/language/expressions/instanceof/prototype-getter-with-primitive.js:
default: "Test262Error: getter for 'prototype' called"
strict mode: "Test262Error: getter for 'prototype' called"
+test/language/expressions/logical-assignment/lgcl-and-assignment-operator-non-simple-lhs.js:
+ default: "Test262: This statement should not be evaluated."
+test/language/expressions/logical-assignment/lgcl-nullish-assignment-operator-non-simple-lhs.js:
+ default: "Test262: This statement should not be evaluated."
+test/language/expressions/logical-assignment/lgcl-or-assignment-operator-non-simple-lhs.js:
+ default: "Test262: This statement should not be evaluated."
test/language/expressions/new/ctorExpr-fn-ref-before-args-eval-fn-wrapup.js:
default: "TypeError: 1 is not a constructor (evaluating 'new x(x = 1)')"
strict mode: "TypeError: 1 is not a constructor (evaluating 'new x(x = 1)')"
Modified: trunk/Source/_javascript_Core/ChangeLog (260118 => 260119)
--- trunk/Source/_javascript_Core/ChangeLog 2020-04-15 06:20:39 UTC (rev 260118)
+++ trunk/Source/_javascript_Core/ChangeLog 2020-04-15 07:02:55 UTC (rev 260119)
@@ -1,3 +1,58 @@
+2020-04-15 Devin Rousso <[email protected]>
+
+ [ESNext] Implement logical assignment operators
+ https://bugs.webkit.org/show_bug.cgi?id=209716
+
+ Reviewed by Ross Kirsling.
+
+ Implement the logical assignment operators proposal, which is now Stage 3. It introduces
+ three new assignment operators which will only store the result of the rhs in the lhs if the
+ lhs meets the given condition:
+ - `??=`, for if the lhs is nullish (`null` or `undefined`)
+ - `||=`, for if the lhs is falsy
+ - `&&=`, for if the lhs is truthy
+
+ This short circuiting can be beneficial as it can avoid a redundant store when used in the
+ common _javascript_ programming pattern of "defaulting" a parameter.
+
+ ```js
+ function foo(x) {
+ x = x || 42;
+ }
+ ```
+
+ If `x` is a truthy value, it would result in the rhs `x` being stored back into the lhs `x`.
+ In some situations, this can have negative unintended side-effects, such as for `innerHTML`.
+
+ Logical assignment operators, however, are defined such that they only store if the rhs is
+ to actually be needed/used, skipping the redundant store and simply returning lhs otherwise.
+
+ In the case of readonly references, this means that an error is only thrown when the
+ assignment occurs, meaning that if the lhs already satisfies the condition it will be used
+ and returned with no error.
+
+ * parser/ParserTokens.h:
+ * parser/Lexer.cpp:
+ (JSC::Lexer<T>::lexWithoutClearingLineTerminator):
+ * parser/Parser.cpp:
+ (JSC::Parser<LexerType>::parseAssignmentExpression):
+
+ * parser/ASTBuilder.h:
+ (JSC::ASTBuilder::makeAssignNode):
+ * parser/Nodes.h:
+ * parser/NodeConstructors.h:
+ (JSC::ShortCircuitReadModifyResolveNode::ShortCircuitReadModifyResolveNode): Added.
+ (JSC::ShortCircuitReadModifyBracketNode::ShortCircuitReadModifyBracketNode): Added.
+ (JSC::ShortCircuitReadModifyDotNode::ShortCircuitReadModifyDotNode): Added.
+ * bytecompiler/NodesCodegen.cpp:
+ (JSC::emitShortCircuitAssignment): Added.
+ (JSC::ShortCircuitReadModifyResolveNode::emitBytecode): Added.
+ (JSC::ShortCircuitReadModifyDotNode::emitBytecode): Added.
+ (JSC::ShortCircuitReadModifyBracketNode::emitBytecode): Added.
+
+ * runtime/OptionsList.h:
+ Add a `useLogicalAssignmentOperators` setting for controlling this feature.
+
2020-04-14 Devin Rousso <[email protected]>
Web Inspector: Debugger: add a Step next that steps by _expression_
Modified: trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp (260118 => 260119)
--- trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp 2020-04-15 06:20:39 UTC (rev 260118)
+++ trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp 2020-04-15 07:02:55 UTC (rev 260119)
@@ -2862,6 +2862,109 @@
return returnResult;
}
+// ------------------------------ ShortCircuitReadModifyResolveNode -----------------------------------
+
+static ALWAYS_INLINE void emitShortCircuitAssignment(BytecodeGenerator& generator, RegisterID* value, Operator oper, Label& afterAssignment)
+{
+ switch (oper) {
+ case Operator::NullishEq:
+ generator.emitJumpIfFalse(generator.emitIsUndefinedOrNull(generator.newTemporary(), value), afterAssignment);
+ break;
+
+ case Operator::OrEq:
+ generator.emitJumpIfTrue(value, afterAssignment);
+ break;
+
+ case Operator::AndEq:
+ generator.emitJumpIfFalse(value, afterAssignment);
+ break;
+
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ break;
+ }
+}
+
+RegisterID* ShortCircuitReadModifyResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
+{
+ JSTextPosition newDivot = divotStart() + m_ident.length();
+
+ Variable var = generator.variable(m_ident);
+ bool isReadOnly = var.isReadOnly();
+
+ if (RefPtr<RegisterID> local = var.local()) {
+ generator.emitTDZCheckIfNecessary(var, local.get(), nullptr);
+
+ if (isReadOnly) {
+ RefPtr<RegisterID> result = local;
+
+ Ref<Label> afterAssignment = generator.newLabel();
+ emitShortCircuitAssignment(generator, result.get(), m_operator, afterAssignment.get());
+
+ result = generator.emitNode(result.get(), m_right); // Execute side effects first.
+ bool threwException = generator.emitReadOnlyExceptionIfNeeded(var);
+
+ if (!threwException)
+ generator.emitProfileType(result.get(), divotStart(), divotEnd());
+
+ generator.emitLabel(afterAssignment.get());
+ return generator.move(dst, result.get());
+ }
+
+ if (generator.leftHandSideNeedsCopy(m_rightHasAssignments, m_right->isPure(generator))) {
+ RefPtr<RegisterID> result = generator.tempDestination(dst);
+ generator.move(result.get(), local.get());
+
+ Ref<Label> afterAssignment = generator.newLabel();
+ emitShortCircuitAssignment(generator, result.get(), m_operator, afterAssignment.get());
+
+ result = generator.emitNode(result.get(), m_right);
+ generator.move(local.get(), result.get());
+ generator.emitProfileType(result.get(), var, divotStart(), divotEnd());
+
+ generator.emitLabel(afterAssignment.get());
+ return generator.move(dst, result.get());
+ }
+
+ RefPtr<RegisterID> result = local;
+
+ Ref<Label> afterAssignment = generator.newLabel();
+ emitShortCircuitAssignment(generator, result.get(), m_operator, afterAssignment.get());
+
+ result = generator.emitNode(result.get(), m_right);
+ generator.emitProfileType(result.get(), var, divotStart(), divotEnd());
+
+ generator.emitLabel(afterAssignment.get());
+ return generator.move(dst, result.get());
+ }
+
+ generator.emitExpressionInfo(newDivot, divotStart(), newDivot);
+ RefPtr<RegisterID> scope = generator.emitResolveScope(nullptr, var);
+
+ RefPtr<RegisterID> result = generator.emitGetFromScope(generator.tempDestination(dst), scope.get(), var, ThrowIfNotFound);
+ generator.emitTDZCheckIfNecessary(var, result.get(), nullptr);
+
+ Ref<Label> afterAssignment = generator.newLabel();
+ emitShortCircuitAssignment(generator, result.get(), m_operator, afterAssignment.get());
+
+ result = generator.emitNode(result.get(), m_right); // Execute side effects first.
+
+ bool threwException = isReadOnly ? generator.emitReadOnlyExceptionIfNeeded(var) : false;
+
+ if (!threwException)
+ generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
+
+ if (!isReadOnly) {
+ result = generator.emitPutToScope(scope.get(), var, result.get(), ThrowIfNotFound, InitializationMode::NotInitialization);
+ generator.emitProfileType(result.get(), var, divotStart(), divotEnd());
+ }
+
+ generator.emitLabel(afterAssignment.get());
+ return generator.move(dst, result.get());
+}
+
+// ------------------------------ AssignResolveNode -----------------------------------
+
static InitializationMode initializationModeForAssignmentContext(AssignmentContext assignmentContext)
{
switch (assignmentContext) {
@@ -2877,8 +2980,6 @@
return InitializationMode::NotInitialization;
}
-// ------------------------------ AssignResolveNode -----------------------------------
-
RegisterID* AssignResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
{
Variable var = generator.variable(m_ident);
@@ -2978,6 +3079,37 @@
return ret;
}
+// ------------------------------ ShortCircuitReadModifyDotNode -----------------------------------
+
+RegisterID* ShortCircuitReadModifyDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
+{
+ RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base, m_rightHasAssignments, m_right->isPure(generator));
+ RefPtr<RegisterID> thisValue;
+
+ RefPtr<RegisterID> result;
+
+ generator.emitExpressionInfo(subexpressionDivot(), subexpressionStart(), subexpressionEnd());
+ if (m_base->isSuperNode()) {
+ thisValue = generator.ensureThis();
+ result = generator.emitGetById(generator.tempDestination(dst), base.get(), thisValue.get(), m_ident);
+ } else
+ result = generator.emitGetById(generator.tempDestination(dst), base.get(), m_ident);
+
+ Ref<Label> afterAssignment = generator.newLabel();
+ emitShortCircuitAssignment(generator, result.get(), m_operator, afterAssignment.get());
+
+ result = generator.emitNode(result.get(), m_right);
+ generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
+ if (m_base->isSuperNode())
+ result = generator.emitPutById(base.get(), thisValue.get(), m_ident, result.get());
+ else
+ result = generator.emitPutById(base.get(), m_ident, result.get());
+ generator.emitProfileType(result.get(), divotStart(), divotEnd());
+
+ generator.emitLabel(afterAssignment.get());
+ return generator.move(dst, result.get());
+}
+
// ------------------------------ AssignErrorNode -----------------------------------
RegisterID* AssignErrorNode::emitBytecode(BytecodeGenerator& generator, RegisterID*)
@@ -3042,6 +3174,38 @@
return updatedValue;
}
+// ------------------------------ ShortCircuitReadModifyBracketNode -----------------------------------
+
+RegisterID* ShortCircuitReadModifyBracketNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
+{
+ RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base, m_subscriptHasAssignments || m_rightHasAssignments, m_subscript->isPure(generator) && m_right->isPure(generator));
+ RefPtr<RegisterID> property = generator.emitNodeForLeftHandSideForProperty(m_subscript, m_rightHasAssignments, m_right->isPure(generator));
+ RefPtr<RegisterID> thisValue;
+
+ RefPtr<RegisterID> result;
+
+ generator.emitExpressionInfo(subexpressionDivot(), subexpressionStart(), subexpressionEnd());
+ if (m_base->isSuperNode()) {
+ thisValue = generator.ensureThis();
+ result = generator.emitGetByVal(generator.tempDestination(dst), base.get(), thisValue.get(), property.get());
+ } else
+ result = generator.emitGetByVal(generator.tempDestination(dst), base.get(), property.get());
+
+ Ref<Label> afterAssignment = generator.newLabel();
+ emitShortCircuitAssignment(generator, result.get(), m_operator, afterAssignment.get());
+
+ result = generator.emitNode(result.get(), m_right);
+ generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
+ if (m_base->isSuperNode())
+ result = generator.emitPutByVal(base.get(), thisValue.get(), property.get(), result.get());
+ else
+ result = generator.emitPutByVal(base.get(), property.get(), result.get());
+ generator.emitProfileType(result.get(), divotStart(), divotEnd());
+
+ generator.emitLabel(afterAssignment.get());
+ return generator.move(dst, result.get());
+}
+
// ------------------------------ CommaNode ------------------------------------
RegisterID* CommaNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
Modified: trunk/Source/_javascript_Core/parser/ASTBuilder.h (260118 => 260119)
--- trunk/Source/_javascript_Core/parser/ASTBuilder.h 2020-04-15 06:20:39 UTC (rev 260118)
+++ trunk/Source/_javascript_Core/parser/ASTBuilder.h 2020-04-15 07:02:55 UTC (rev 260119)
@@ -1548,6 +1548,7 @@
if (loc->isResolveNode()) {
ResolveNode* resolve = static_cast<ResolveNode*>(loc);
+
if (op == Operator::Equal) {
if (expr->isBaseFuncExprNode()) {
auto metadata = static_cast<BaseFuncExprNode*>(expr)->metadata();
@@ -1558,21 +1559,42 @@
setExceptionLocation(node, start, divot, end);
return node;
}
+
+ if (op == Operator::NullishEq || op == Operator::OrEq || op == Operator::AndEq)
+ return new (m_parserArena) ShortCircuitReadModifyResolveNode(location, resolve->identifier(), op, expr, exprHasAssignments, divot, start, end);
+
return new (m_parserArena) ReadModifyResolveNode(location, resolve->identifier(), op, expr, exprHasAssignments, divot, start, end);
}
+
if (loc->isBracketAccessorNode()) {
BracketAccessorNode* bracket = static_cast<BracketAccessorNode*>(loc);
+
if (op == Operator::Equal)
return new (m_parserArena) AssignBracketNode(location, bracket->base(), bracket->subscript(), expr, locHasAssignments, exprHasAssignments, bracket->divot(), start, end);
+
+ if (op == Operator::NullishEq || op == Operator::OrEq || op == Operator::AndEq) {
+ auto* node = new (m_parserArena) ShortCircuitReadModifyBracketNode(location, bracket->base(), bracket->subscript(), op, expr, locHasAssignments, exprHasAssignments, divot, start, end);
+ node->setSubexpressionInfo(bracket->divot(), bracket->divotEnd().offset);
+ return node;
+ }
+
ReadModifyBracketNode* node = new (m_parserArena) ReadModifyBracketNode(location, bracket->base(), bracket->subscript(), op, expr, locHasAssignments, exprHasAssignments, divot, start, end);
node->setSubexpressionInfo(bracket->divot(), bracket->divotEnd().offset);
return node;
}
+
ASSERT(loc->isDotAccessorNode());
DotAccessorNode* dot = static_cast<DotAccessorNode*>(loc);
+
if (op == Operator::Equal)
return new (m_parserArena) AssignDotNode(location, dot->base(), dot->identifier(), expr, exprHasAssignments, dot->divot(), start, end);
+ if (op == Operator::NullishEq || op == Operator::OrEq || op == Operator::AndEq) {
+ auto* node = new (m_parserArena) ShortCircuitReadModifyDotNode(location, dot->base(), dot->identifier(), op, expr, exprHasAssignments, divot, start, end);
+ node->setSubexpressionInfo(dot->divot(), dot->divotEnd().offset);
+ return node;
+ }
+
ReadModifyDotNode* node = new (m_parserArena) ReadModifyDotNode(location, dot->base(), dot->identifier(), op, expr, exprHasAssignments, divot, start, end);
node->setSubexpressionInfo(dot->divot(), dot->divotEnd().offset);
return node;
Modified: trunk/Source/_javascript_Core/parser/Lexer.cpp (260118 => 260119)
--- trunk/Source/_javascript_Core/parser/Lexer.cpp 2020-04-15 06:20:39 UTC (rev 260118)
+++ trunk/Source/_javascript_Core/parser/Lexer.cpp 2020-04-15 07:02:55 UTC (rev 260119)
@@ -2086,6 +2086,11 @@
shift();
if (m_current == '&') {
shift();
+ if (UNLIKELY(Options::useLogicalAssignmentOperators() && m_current == '=')) {
+ shift();
+ token = ANDEQUAL;
+ break;
+ }
token = AND;
break;
}
@@ -2123,6 +2128,11 @@
}
if (m_current == '|') {
shift();
+ if (UNLIKELY(Options::useLogicalAssignmentOperators() && m_current == '=')) {
+ shift();
+ token = OREQUAL;
+ break;
+ }
token = OR;
break;
}
@@ -2159,6 +2169,11 @@
shift();
if (m_current == '?') {
shift();
+ if (UNLIKELY(Options::useLogicalAssignmentOperators() && m_current == '=')) {
+ shift();
+ token = NULLISHEQUAL;
+ break;
+ }
token = COALESCE;
break;
}
Modified: trunk/Source/_javascript_Core/parser/NodeConstructors.h (260118 => 260119)
--- trunk/Source/_javascript_Core/parser/NodeConstructors.h 2020-04-15 06:20:39 UTC (rev 260118)
+++ trunk/Source/_javascript_Core/parser/NodeConstructors.h 2020-04-15 07:02:55 UTC (rev 260119)
@@ -718,6 +718,16 @@
{
}
+ inline ShortCircuitReadModifyResolveNode::ShortCircuitReadModifyResolveNode(const JSTokenLocation& location, const Identifier& ident, Operator oper, ExpressionNode* right, bool rightHasAssignments, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd)
+ : ExpressionNode(location)
+ , ThrowableExpressionData(divot, divotStart, divotEnd)
+ , m_ident(ident)
+ , m_right(right)
+ , m_operator(oper)
+ , m_rightHasAssignments(rightHasAssignments)
+ {
+ }
+
inline AssignResolveNode::AssignResolveNode(const JSTokenLocation& location, const Identifier& ident, ExpressionNode* right, AssignmentContext assignmentContext)
: ExpressionNode(location)
, m_ident(ident)
@@ -739,6 +749,18 @@
{
}
+ inline ShortCircuitReadModifyBracketNode::ShortCircuitReadModifyBracketNode(const JSTokenLocation& location, ExpressionNode* base, ExpressionNode* subscript, Operator oper, ExpressionNode* right, bool subscriptHasAssignments, bool rightHasAssignments, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd)
+ : ExpressionNode(location)
+ , ThrowableSubExpressionData(divot, divotStart, divotEnd)
+ , m_base(base)
+ , m_subscript(subscript)
+ , m_right(right)
+ , m_operator(oper)
+ , m_subscriptHasAssignments(subscriptHasAssignments)
+ , m_rightHasAssignments(rightHasAssignments)
+ {
+ }
+
inline AssignBracketNode::AssignBracketNode(const JSTokenLocation& location, ExpressionNode* base, ExpressionNode* subscript, ExpressionNode* right, bool subscriptHasAssignments, bool rightHasAssignments, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd)
: ExpressionNode(location)
, ThrowableExpressionData(divot, divotStart, divotEnd)
@@ -771,6 +793,17 @@
{
}
+ inline ShortCircuitReadModifyDotNode::ShortCircuitReadModifyDotNode(const JSTokenLocation& location, ExpressionNode* base, const Identifier& ident, Operator oper, ExpressionNode* right, bool rightHasAssignments, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd)
+ : ExpressionNode(location)
+ , ThrowableSubExpressionData(divot, divotStart, divotEnd)
+ , m_base(base)
+ , m_ident(ident)
+ , m_right(right)
+ , m_operator(oper)
+ , m_rightHasAssignments(rightHasAssignments)
+ {
+ }
+
inline AssignErrorNode::AssignErrorNode(const JSTokenLocation& location, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd)
: ExpressionNode(location)
, ThrowableExpressionData(divot, divotStart, divotEnd)
Modified: trunk/Source/_javascript_Core/parser/Nodes.h (260118 => 260119)
--- trunk/Source/_javascript_Core/parser/Nodes.h 2020-04-15 06:20:39 UTC (rev 260118)
+++ trunk/Source/_javascript_Core/parser/Nodes.h 2020-04-15 07:02:55 UTC (rev 260119)
@@ -68,6 +68,9 @@
BitOrEq,
ModEq,
PowEq,
+ NullishEq,
+ OrEq,
+ AndEq,
LShift,
RShift,
URShift
@@ -1389,6 +1392,19 @@
bool m_rightHasAssignments;
};
+ class ShortCircuitReadModifyResolveNode final : public ExpressionNode, public ThrowableExpressionData {
+ public:
+ ShortCircuitReadModifyResolveNode(const JSTokenLocation&, const Identifier&, Operator, ExpressionNode* right, bool rightHasAssignments, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd);
+
+ private:
+ RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+
+ const Identifier& m_ident;
+ ExpressionNode* m_right;
+ Operator m_operator;
+ bool m_rightHasAssignments;
+ };
+
class AssignResolveNode final : public ExpressionNode, public ThrowableExpressionData {
public:
AssignResolveNode(const JSTokenLocation&, const Identifier&, ExpressionNode* right, AssignmentContext);
@@ -1418,6 +1434,21 @@
bool m_rightHasAssignments : 1;
};
+ class ShortCircuitReadModifyBracketNode final : public ExpressionNode, public ThrowableSubExpressionData {
+ public:
+ ShortCircuitReadModifyBracketNode(const JSTokenLocation&, ExpressionNode* base, ExpressionNode* subscript, Operator, ExpressionNode* right, bool subscriptHasAssignments, bool rightHasAssignments, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd);
+
+ private:
+ RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+
+ ExpressionNode* m_base;
+ ExpressionNode* m_subscript;
+ ExpressionNode* m_right;
+ Operator m_operator;
+ bool m_subscriptHasAssignments : 1;
+ bool m_rightHasAssignments : 1;
+ };
+
class AssignBracketNode final : public ExpressionNode, public ThrowableExpressionData {
public:
AssignBracketNode(const JSTokenLocation&, ExpressionNode* base, ExpressionNode* subscript, ExpressionNode* right, bool subscriptHasAssignments, bool rightHasAssignments, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd);
@@ -1459,6 +1490,20 @@
bool m_rightHasAssignments : 1;
};
+ class ShortCircuitReadModifyDotNode final : public ExpressionNode, public ThrowableSubExpressionData {
+ public:
+ ShortCircuitReadModifyDotNode(const JSTokenLocation&, ExpressionNode* base, const Identifier&, Operator, ExpressionNode* right, bool rightHasAssignments, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd);
+
+ private:
+ RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+
+ ExpressionNode* m_base;
+ const Identifier& m_ident;
+ ExpressionNode* m_right;
+ Operator m_operator;
+ bool m_rightHasAssignments : 1;
+ };
+
class AssignErrorNode final : public ExpressionNode, public ThrowableExpressionData {
public:
AssignErrorNode(const JSTokenLocation&, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd);
Modified: trunk/Source/_javascript_Core/parser/Parser.cpp (260118 => 260119)
--- trunk/Source/_javascript_Core/parser/Parser.cpp 2020-04-15 06:20:39 UTC (rev 260118)
+++ trunk/Source/_javascript_Core/parser/Parser.cpp 2020-04-15 07:02:55 UTC (rev 260119)
@@ -3847,7 +3847,7 @@
failIfFalse(lhs, "Cannot parse _expression_");
if (initialNonLHSCount != m_parserState.nonLHSCount) {
- if (m_token.m_type >= EQUAL && m_token.m_type <= BITOREQUAL)
+ if (m_token.m_type >= EQUAL && m_token.m_type <= ANDEQUAL)
semanticFail("Left hand side of operator '", getToken(), "' must be a reference");
return lhs;
@@ -3871,6 +3871,9 @@
case BITOREQUAL: op = Operator::BitOrEq; break;
case MODEQUAL: op = Operator::ModEq; break;
case POWEQUAL: op = Operator::PowEq; break;
+ case NULLISHEQUAL: op = Operator::NullishEq; break;
+ case OREQUAL: op = Operator::OrEq; break;
+ case ANDEQUAL: op = Operator::AndEq; break;
default:
goto end;
}
@@ -3890,7 +3893,7 @@
lhs = parseAssignmentExpression(context);
failIfFalse(lhs, "Cannot parse the right hand side of an assignment _expression_");
if (initialNonLHSCount != m_parserState.nonLHSCount) {
- if (m_token.m_type >= EQUAL && m_token.m_type <= BITOREQUAL)
+ if (m_token.m_type >= EQUAL && m_token.m_type <= ANDEQUAL)
semanticFail("Left hand side of operator '", getToken(), "' must be a reference");
break;
}
Modified: trunk/Source/_javascript_Core/parser/ParserTokens.h (260118 => 260119)
--- trunk/Source/_javascript_Core/parser/ParserTokens.h 2020-04-15 06:20:39 UTC (rev 260118)
+++ trunk/Source/_javascript_Core/parser/ParserTokens.h 2020-04-15 07:02:55 UTC (rev 260119)
@@ -134,6 +134,9 @@
BITANDEQUAL,
BITXOREQUAL,
BITOREQUAL,
+ NULLISHEQUAL,
+ OREQUAL,
+ ANDEQUAL,
DOTDOTDOT,
ARROWFUNCTION,
QUESTIONDOT,
Modified: trunk/Source/_javascript_Core/runtime/OptionsList.h (260118 => 260119)
--- trunk/Source/_javascript_Core/runtime/OptionsList.h 2020-04-15 06:20:39 UTC (rev 260118)
+++ trunk/Source/_javascript_Core/runtime/OptionsList.h 2020-04-15 07:02:55 UTC (rev 260119)
@@ -500,6 +500,7 @@
v(Bool, forceOSRExitToLLInt, false, Normal, "If true, we always exit to the LLInt. If false, we exit to whatever is most convenient.") \
v(Unsigned, getByValICMaxNumberOfIdentifiers, 4, Normal, "Number of identifiers we see in the LLInt that could cause us to bail on generating an IC for get_by_val.") \
v(Bool, usePublicClassFields, true, Normal, "If true, the parser will understand public data fields inside classes.") \
+ v(Bool, useLogicalAssignmentOperators, false, Normal, "Enable support for \?\?=, ||=, and &&= logical assignment operators.") \
v(Bool, useRandomizingExecutableIslandAllocation, false, Normal, "For the arm64 ExecutableAllocator, if true, select which region to use randomly. This is useful for testing that jump islands work.") \
enum OptionEquivalence {
Modified: trunk/Tools/ChangeLog (260118 => 260119)
--- trunk/Tools/ChangeLog 2020-04-15 06:20:39 UTC (rev 260118)
+++ trunk/Tools/ChangeLog 2020-04-15 07:02:55 UTC (rev 260119)
@@ -1,3 +1,12 @@
+2020-04-15 Devin Rousso <[email protected]>
+
+ [ESNext] Implement logical assignment operators
+ https://bugs.webkit.org/show_bug.cgi?id=209716
+
+ Reviewed by Ross Kirsling.
+
+ * Scripts/run-jsc-stress-tests:
+
2020-04-14 Jer Noble <[email protected]>
WKTR always enables capturing audio/video in GPUProcess
Modified: trunk/Tools/Scripts/run-jsc-stress-tests (260118 => 260119)
--- trunk/Tools/Scripts/run-jsc-stress-tests 2020-04-15 06:20:39 UTC (rev 260118)
+++ trunk/Tools/Scripts/run-jsc-stress-tests 2020-04-15 07:02:55 UTC (rev 260119)
@@ -787,6 +787,10 @@
run("mini-mode", "--forceMiniVMMode=true", *optionalTestSpecificOptions)
end
+def runLogicalAssignmentOperatorsEnabled(*optionalTestSpecificOptions)
+ run("logical-assignment-operators-enabled", "--useLogicalAssignmentOperators=true" , *(FTL_OPTIONS + optionalTestSpecificOptions))
+end
+
def defaultRun
if $mode == "quick"
defaultQuickRun