summaryrefslogtreecommitdiff
path: root/js
diff options
context:
space:
mode:
authorFranklinDM <mrmineshafter17@gmail.com>2022-05-04 02:16:05 +0800
committerFranklinDM <mrmineshafter17@gmail.com>2022-05-04 14:57:19 +0800
commit006b8f5c6e23a0bfb38d10c0f7c95b610b79c49d (patch)
treec7c0f507b8db88ef5b93b2e0e71d4481bec28a49 /js
parent152974a8fe4ea4a3bcbf1acc9f0eee7e1101216d (diff)
downloaduxp-006b8f5c6e23a0bfb38d10c0f7c95b610b79c49d.tar.gz
Issue #1658 - Part 8: Update tests
Diffstat (limited to 'js')
-rw-r--r--js/src/jit-test/tests/basic/bug1644839-2.js5
-rw-r--r--js/src/jit-test/tests/basic/bug1644839.js5
-rw-r--r--js/src/jit-test/tests/optional-chain/call-ignore-rval.js34
-rw-r--r--js/src/jit-test/tests/optional-chain/fun-call-or-apply.js60
-rw-r--r--js/src/tests/non262/expressions/browser.js0
-rw-r--r--js/src/tests/non262/expressions/optional-chain-class-heritage.js10
-rw-r--r--js/src/tests/non262/expressions/optional-chain-first-expression.js92
-rw-r--r--js/src/tests/non262/expressions/optional-chain-super-elem.js12
-rw-r--r--js/src/tests/non262/expressions/optional-chain-tdz.js28
-rw-r--r--js/src/tests/non262/expressions/optional-chain.js223
-rw-r--r--js/src/tests/non262/expressions/shell.js0
-rw-r--r--js/src/tests/non262/shell.js0
-rw-r--r--js/src/tests/test262/language/expressions/assignment/dstr/array-elem-nested-memberexpr-optchain-prop-ref-init.js57
-rw-r--r--js/src/tests/test262/language/expressions/assignment/dstr/array-elem-put-obj-literal-optchain-prop-ref-init.js60
-rw-r--r--js/src/tests/test262/language/expressions/assignment/dstr/obj-prop-elem-target-memberexpr-optchain-prop-ref-init.js57
-rw-r--r--js/src/tests/test262/language/expressions/assignment/dstr/obj-prop-elem-target-obj-literal-optchain-prop-ref-init.js60
-rw-r--r--js/src/tests/test262/language/expressions/assignment/dstr/shell.js0
-rw-r--r--js/src/tests/test262/language/expressions/assignment/shell.js0
-rw-r--r--js/src/tests/test262/language/expressions/shell.js16
-rw-r--r--js/src/tests/test262/language/optional-chaining/call-expression-super-no-base.js24
-rw-r--r--js/src/tests/test262/language/optional-chaining/call-expression.js77
-rw-r--r--js/src/tests/test262/language/optional-chaining/early-errors-tail-position-null-op-template-string-esi.js26
-rw-r--r--js/src/tests/test262/language/optional-chaining/early-errors-tail-position-null-op-template-string.js23
-rw-r--r--js/src/tests/test262/language/optional-chaining/early-errors-tail-position-null-optchain-template-string-esi.js26
-rw-r--r--js/src/tests/test262/language/optional-chaining/early-errors-tail-position-null-optchain-template-string.js23
-rw-r--r--js/src/tests/test262/language/optional-chaining/early-errors-tail-position-op-template-string-esi.js28
-rw-r--r--js/src/tests/test262/language/optional-chaining/early-errors-tail-position-op-template-string.js25
-rw-r--r--js/src/tests/test262/language/optional-chaining/early-errors-tail-position-optchain-template-string-esi.js28
-rw-r--r--js/src/tests/test262/language/optional-chaining/early-errors-tail-position-optchain-template-string.js25
-rw-r--r--js/src/tests/test262/language/optional-chaining/eval-optional-call.js41
-rw-r--r--js/src/tests/test262/language/optional-chaining/iteration-statement-do.js20
-rw-r--r--js/src/tests/test262/language/optional-chaining/iteration-statement-for-await-of.js36
-rw-r--r--js/src/tests/test262/language/optional-chaining/iteration-statement-for-in.js24
-rw-r--r--js/src/tests/test262/language/optional-chaining/iteration-statement-for-of-type-error.js30
-rw-r--r--js/src/tests/test262/language/optional-chaining/iteration-statement-for.js45
-rw-r--r--js/src/tests/test262/language/optional-chaining/iteration-statement-while.js20
-rw-r--r--js/src/tests/test262/language/optional-chaining/member-expression-async-identifier.js33
-rw-r--r--js/src/tests/test262/language/optional-chaining/member-expression-async-literal.js20
-rw-r--r--js/src/tests/test262/language/optional-chaining/member-expression-async-this.js21
-rw-r--r--js/src/tests/test262/language/optional-chaining/member-expression.js106
-rw-r--r--js/src/tests/test262/language/optional-chaining/new-target-optional-call.js32
-rw-r--r--js/src/tests/test262/language/optional-chaining/optional-call-preserves-this.js29
-rw-r--r--js/src/tests/test262/language/optional-chaining/optional-chain-async-optional-chain-square-brackets.js29
-rw-r--r--js/src/tests/test262/language/optional-chaining/optional-chain-async-square-brackets.js25
-rw-r--r--js/src/tests/test262/language/optional-chaining/optional-chain-expression-optional-expression.js22
-rw-r--r--js/src/tests/test262/language/optional-chaining/optional-chain-prod-arguments.js21
-rw-r--r--js/src/tests/test262/language/optional-chaining/optional-chain-prod-expression.js44
-rw-r--r--js/src/tests/test262/language/optional-chaining/optional-chain-prod-identifiername.js40
-rw-r--r--js/src/tests/test262/language/optional-chaining/optional-chain.js52
-rw-r--r--js/src/tests/test262/language/optional-chaining/optional-expression.js29
-rw-r--r--js/src/tests/test262/language/optional-chaining/punctuator-decimal-lookahead.js17
-rw-r--r--js/src/tests/test262/language/optional-chaining/runtime-semantics-evaluation.js20
-rw-r--r--js/src/tests/test262/language/optional-chaining/shell.js0
-rw-r--r--js/src/tests/test262/language/optional-chaining/short-circuiting.js24
-rw-r--r--js/src/tests/test262/language/optional-chaining/static-semantics-simple-assignment.js24
-rw-r--r--js/src/tests/test262/language/optional-chaining/super-property-optional-call.js32
-rw-r--r--js/src/tests/test262/language/optional-chaining/update-expression-postfix.js24
-rw-r--r--js/src/tests/test262/language/optional-chaining/update-expression-prefix.js24
-rw-r--r--js/src/tests/test262/language/statements/for-in/dstr/array-elem-nested-memberexpr-optchain-prop-ref-init.js66
-rw-r--r--js/src/tests/test262/language/statements/for-in/dstr/array-elem-nested-memberexpr-optchain-prop-ref.js66
-rw-r--r--js/src/tests/test262/language/statements/for-in/dstr/array-elem-put-obj-literal-optchain-prop-ref-init.js69
-rw-r--r--js/src/tests/test262/language/statements/for-in/dstr/array-elem-put-obj-literal-optchain-prop-ref.js69
-rw-r--r--js/src/tests/test262/language/statements/for-in/dstr/obj-prop-elem-target-memberexpr-optchain-prop-ref-init.js66
-rw-r--r--js/src/tests/test262/language/statements/for-in/dstr/obj-prop-elem-target-memberexpr-optchain-prop-ref.js66
-rw-r--r--js/src/tests/test262/language/statements/for-in/dstr/obj-prop-elem-target-obj-literal-optchain-prop-ref-init.js69
-rw-r--r--js/src/tests/test262/language/statements/for-in/dstr/obj-prop-elem-target-obj-literal-optchain-prop-ref.js69
-rw-r--r--js/src/tests/test262/language/statements/for-in/dstr/shell.js0
-rw-r--r--js/src/tests/test262/language/statements/for-in/shell.js0
-rw-r--r--js/src/tests/test262/language/statements/for-of/dstr/array-elem-nested-memberexpr-optchain-prop-ref-init.js66
-rw-r--r--js/src/tests/test262/language/statements/for-of/dstr/array-elem-nested-memberexpr-optchain-prop-ref.js66
-rw-r--r--js/src/tests/test262/language/statements/for-of/dstr/array-elem-put-obj-literal-optchain-prop-ref-init.js69
-rw-r--r--js/src/tests/test262/language/statements/for-of/dstr/array-elem-put-obj-literal-optchain-prop-ref.js69
-rw-r--r--js/src/tests/test262/language/statements/for-of/dstr/obj-prop-elem-target-memberexpr-optchain-prop-ref-init.js66
-rw-r--r--js/src/tests/test262/language/statements/for-of/dstr/obj-prop-elem-target-memberexpr-optchain-prop-ref.js66
-rw-r--r--js/src/tests/test262/language/statements/for-of/dstr/obj-prop-elem-target-obj-literal-optchain-prop-ref-init.js69
-rw-r--r--js/src/tests/test262/language/statements/for-of/dstr/obj-prop-elem-target-obj-literal-optchain-prop-ref.js69
-rw-r--r--js/src/tests/test262/language/statements/for-of/dstr/shell.js0
-rw-r--r--js/src/tests/test262/language/statements/for-of/shell.js0
-rw-r--r--js/src/tests/test262/language/statements/shell.js0
79 files changed, 2988 insertions, 0 deletions
diff --git a/js/src/jit-test/tests/basic/bug1644839-2.js b/js/src/jit-test/tests/basic/bug1644839-2.js
new file mode 100644
index 0000000000..62550670ec
--- /dev/null
+++ b/js/src/jit-test/tests/basic/bug1644839-2.js
@@ -0,0 +1,5 @@
+// |jit-test| skip-if: !('oomTest' in this)
+var code = `
+ (\`\${key}: \${(args[1]?.toString)?.()}\`)
+`;
+oomTest(function() { return parseModule(code); }); \ No newline at end of file
diff --git a/js/src/jit-test/tests/basic/bug1644839.js b/js/src/jit-test/tests/basic/bug1644839.js
new file mode 100644
index 0000000000..1a9ec3dd8d
--- /dev/null
+++ b/js/src/jit-test/tests/basic/bug1644839.js
@@ -0,0 +1,5 @@
+// |jit-test| skip-if: !('oomTest' in this)
+var code = `
+ (\`\${key}: \${args[1]?.toString()}\`)
+`;
+oomTest(function() { return parseModule(code); }); \ No newline at end of file
diff --git a/js/src/jit-test/tests/optional-chain/call-ignore-rval.js b/js/src/jit-test/tests/optional-chain/call-ignore-rval.js
new file mode 100644
index 0000000000..c5fd2fe975
--- /dev/null
+++ b/js/src/jit-test/tests/optional-chain/call-ignore-rval.js
@@ -0,0 +1,34 @@
+// Tests for JSOp::CallIgnoresRv in optional chains.
+
+// Note:: IgnoresReturnValueNative is supported for Array.prototype.splice.
+
+// Test for optional call.
+function testOptionalCall() {
+ for (var i = 0; i < 100; ++i) {
+ var x = [1, 2, 3];
+ x.splice?.(0);
+ }
+}
+
+for (var i = 0; i < 5; ++i) { testOptionalCall(); }
+
+// Test for optional prop directly followed by call.
+function testOptionalProp() {
+ for (var i = 0; i < 100; ++i) {
+ var x = [1, 2, 3];
+ x?.splice(0);
+ }
+}
+
+for (var i = 0; i < 5; ++i) { testOptionalProp(); }
+
+// Test for call in optional chain expression.
+function testOptionalChain() {
+ for (var i = 0; i < 100; ++i) {
+ var x = [1, 2, 3];
+ var o = {x};
+ o?.x.splice(0);
+ }
+}
+
+for (var i = 0; i < 5; ++i) { testOptionalChain(); }
diff --git a/js/src/jit-test/tests/optional-chain/fun-call-or-apply.js b/js/src/jit-test/tests/optional-chain/fun-call-or-apply.js
new file mode 100644
index 0000000000..ed25de9498
--- /dev/null
+++ b/js/src/jit-test/tests/optional-chain/fun-call-or-apply.js
@@ -0,0 +1,60 @@
+// Tests for JSOp::FunCall and JSOp::FunApply in optional calls.
+
+function f1() {
+ return 0;
+}
+function f2(a) {
+ return a * 2;
+}
+
+function funCall(fn) {
+ // Without arguments.
+ for (var i = 0; i < 100; ++i) {
+ assertEq(f1?.call(), 0);
+ }
+
+ // Only this-arg.
+ for (var i = 0; i < 100; ++i) {
+ assertEq(f1?.call(null), 0);
+ }
+
+ // With one arg.
+ for (var i = 0; i < 100; ++i) {
+ assertEq(f1?.call(null, 1), 0);
+ assertEq(f2?.call(null, 5), 10);
+ }
+
+ // With multiple args.
+ for (var i = 0; i < 100; ++i) {
+ assertEq(f1?.call(null, 1, 2, 3), 0);
+ assertEq(f2?.call(null, 4, 5, 6), 8);
+ }
+}
+
+for (var i = 0; i < 5; ++i) { funCall(); }
+
+function funApply(fn) {
+ // Without arguments.
+ for (var i = 0; i < 100; ++i) {
+ assertEq(f1?.apply(), 0);
+ }
+
+ // Only this-arg.
+ for (var i = 0; i < 100; ++i) {
+ assertEq(f1?.apply(null), 0);
+ }
+
+ // With one arg.
+ for (var i = 0; i < 100; ++i) {
+ assertEq(f1?.apply(null, [1]), 0);
+ assertEq(f2?.apply(null, [5]), 10);
+ }
+
+ // With multiple args.
+ for (var i = 0; i < 100; ++i) {
+ assertEq(f1?.apply(null, [1, 2, 3]), 0);
+ assertEq(f2?.apply(null, [4, 5, 6]), 8);
+ }
+}
+
+for (var i = 0; i < 5; ++i) { funApply(); } \ No newline at end of file
diff --git a/js/src/tests/non262/expressions/browser.js b/js/src/tests/non262/expressions/browser.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/non262/expressions/browser.js
diff --git a/js/src/tests/non262/expressions/optional-chain-class-heritage.js b/js/src/tests/non262/expressions/optional-chain-class-heritage.js
new file mode 100644
index 0000000000..14a99c6392
--- /dev/null
+++ b/js/src/tests/non262/expressions/optional-chain-class-heritage.js
@@ -0,0 +1,10 @@
+// Optional expression can be part of a class heritage expression.
+
+var a = {b: null};
+
+class C extends a?.b {}
+
+assertEq(Object.getPrototypeOf(C.prototype), null);
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/expressions/optional-chain-first-expression.js b/js/src/tests/non262/expressions/optional-chain-first-expression.js
new file mode 100644
index 0000000000..89912aec4a
--- /dev/null
+++ b/js/src/tests/non262/expressions/optional-chain-first-expression.js
@@ -0,0 +1,92 @@
+// Verify bytecode emitter accepts all valid optional chain first expressions.
+
+const expressions = [
+ // https://tc39.es/ecma262/#sec-primary-expression
+ "this",
+ "ident",
+ "null",
+ "true",
+ "false",
+ "123",
+ "123n",
+ "'str'",
+ "[]",
+ "{}",
+ "function(){}",
+ "class{}",
+ "function*(){}",
+ "async function(){}",
+ "async function*(){}",
+ "/a/",
+ "`str`",
+ "(a + b)",
+
+ // https://tc39.es/ecma262/#sec-left-hand-side-expressions
+ "a[b]",
+ "a.b",
+ "a``",
+ "super[a]",
+ "super.a",
+ "new.target",
+ "import.meta",
+ "new C()",
+ "new C",
+ "f()",
+ "super()",
+ "a?.b",
+ "a?.[b]",
+ "a?.()",
+ "a?.``",
+];
+
+function tryParse(s, f = Function) {
+ try { f(s); } catch {}
+}
+
+function tryRun(s, f = Function) {
+ try { f(s)(); } catch {}
+}
+
+for (let expr of expressions) {
+ // Evaluate in an expression context.
+ tryRun(`void (${expr}?.());`);
+ tryRun(`void (${expr}?.p());`);
+
+ // Also try parenthesized.
+ tryRun(`void ((${expr})?.());`);
+ tryRun(`void ((${expr})?.p());`);
+}
+
+function inClassConstructor(s) {
+ return `class C { constructor() { ${s} } }`;
+}
+
+for (let expr of ["super[a]", "super.a", "super()"]) {
+ // Evaluate in an expression context.
+ tryRun(inClassConstructor(`void (${expr}?.());`));
+ tryRun(inClassConstructor(`void (${expr}?.p());`));
+
+ // Also try parenthesized.
+ tryRun(inClassConstructor(`void ((${expr})?.());`));
+ tryRun(inClassConstructor(`void ((${expr})?.p());`));
+}
+
+if (typeof parseModule === "function") {
+ const expressions = [
+ "import.meta",
+ "import('')",
+ ];
+
+ for (let expr of expressions) {
+ // Evaluate in an expression context.
+ tryParse(`void (${expr}?.());`, parseModule);
+ tryParse(`void (${expr}?.p());`, parseModule);
+
+ // Also try parenthesized.
+ tryParse(`void ((${expr})?.());`, parseModule);
+ tryParse(`void ((${expr})?.p());`, parseModule);
+ }
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/expressions/optional-chain-super-elem.js b/js/src/tests/non262/expressions/optional-chain-super-elem.js
new file mode 100644
index 0000000000..3b912a9ada
--- /dev/null
+++ b/js/src/tests/non262/expressions/optional-chain-super-elem.js
@@ -0,0 +1,12 @@
+// Don't assert.
+
+var obj = {
+ m() {
+ super[0]?.a
+ }
+};
+
+obj.m();
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/expressions/optional-chain-tdz.js b/js/src/tests/non262/expressions/optional-chain-tdz.js
new file mode 100644
index 0000000000..e12d0fb860
--- /dev/null
+++ b/js/src/tests/non262/expressions/optional-chain-tdz.js
@@ -0,0 +1,28 @@
+// Test TDZ for optional chaining.
+
+// TDZ for lexical |let| bindings with optional chaining.
+{
+ assertThrowsInstanceOf(() => {
+ const Null = null;
+ Null?.[b];
+ b = 0;
+ let b;
+ }, ReferenceError);
+
+ assertThrowsInstanceOf(() => {
+ const Null = null;
+ Null?.[b]();
+ b = 0;
+ let b;
+ }, ReferenceError);
+
+ assertThrowsInstanceOf(() => {
+ const Null = null;
+ delete Null?.[b];
+ b = 0;
+ let b;
+ }, ReferenceError);
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/expressions/optional-chain.js b/js/src/tests/non262/expressions/optional-chain.js
new file mode 100644
index 0000000000..04e0909359
--- /dev/null
+++ b/js/src/tests/non262/expressions/optional-chain.js
@@ -0,0 +1,223 @@
+var BUGNUMBER = 1566143;
+var summary = "Implement the Optional Chain operator (?.) proposal";
+
+print(BUGNUMBER + ": " + summary);
+
+// These tests are originally from webkit.
+// webkit specifics have been removed and error messages have been updated.
+function shouldBe(actual, expected) {
+ if (actual !== expected)
+ throw new Error(`expected ${expected} but got ${actual}`);
+}
+
+function shouldThrowSyntaxError(script) {
+ let error;
+ try {
+ eval(script);
+ } catch (e) {
+ error = e;
+ }
+
+ if (!(error instanceof SyntaxError))
+ throw new Error('Expected SyntaxError!');
+}
+
+function shouldNotThrowSyntaxError(script) {
+ let error;
+ try {
+ eval(script);
+ } catch (e) {
+ error = e;
+ }
+
+ if ((error instanceof SyntaxError))
+ throw new Error('Unxpected SyntaxError!');
+}
+
+function shouldThrowTypeError(func, messagePrefix) {
+ let error;
+ try {
+ func();
+ } catch (e) {
+ error = e;
+ }
+
+ if (!(error instanceof TypeError))
+ throw new Error('Expected TypeError!');
+}
+function testBasicSuccessCases() {
+ shouldBe(undefined?.valueOf(), undefined);
+ shouldBe(null?.valueOf(), undefined);
+ shouldBe(true?.valueOf(), true);
+ shouldBe(false?.valueOf(), false);
+ shouldBe(0?.valueOf(), 0);
+ shouldBe(1?.valueOf(), 1);
+ shouldBe(''?.valueOf(), '');
+ shouldBe('hi'?.valueOf(), 'hi');
+ shouldBe(({})?.constructor, Object);
+ shouldBe(({ x: 'hi' })?.x, 'hi');
+ shouldBe([]?.length, 0);
+ shouldBe(['hi']?.length, 1);
+
+ shouldBe(undefined?.['valueOf'](), undefined);
+ shouldBe(null?.['valueOf'](), undefined);
+ shouldBe(true?.['valueOf'](), true);
+ shouldBe(false?.['valueOf'](), false);
+ shouldBe(0?.['valueOf'](), 0);
+ shouldBe(1?.['valueOf'](), 1);
+ shouldBe(''?.['valueOf'](), '');
+ shouldBe('hi'?.['valueOf'](), 'hi');
+ shouldBe(({})?.['constructor'], Object);
+ shouldBe(({ x: 'hi' })?.['x'], 'hi');
+ shouldBe([]?.['length'], 0);
+ shouldBe(['hi']?.[0], 'hi');
+
+ shouldBe(undefined?.(), undefined);
+ shouldBe(null?.(), undefined);
+ shouldBe((() => 3)?.(), 3);
+}
+
+function testBasicFailureCases() {
+ shouldThrowTypeError(() => true?.(), 'true is not a function');
+ shouldThrowTypeError(() => false?.(), 'false is not a function');
+ shouldThrowTypeError(() => 0?.(), '0 is not a function');
+ shouldThrowTypeError(() => 1?.(), '1 is not a function');
+ shouldThrowTypeError(() => ''?.(), '"" is not a function');
+ shouldThrowTypeError(() => 'hi'?.(), '"hi" is not a function');
+ shouldThrowTypeError(() => ({})?.(), '({}) is not a function');
+ shouldThrowTypeError(() => ({ x: 'hi' })?.(), '({x:"hi"}) is not a function');
+ shouldThrowTypeError(() => []?.(), '[] is not a function');
+ shouldThrowTypeError(() => ['hi']?.(), '[...] is not a function');
+}
+
+testBasicSuccessCases();
+
+testBasicFailureCases();
+
+shouldThrowTypeError(() => ({})?.i(), '(intermediate value).i is not a function');
+shouldBe(({}).i?.(), undefined);
+shouldBe(({})?.i?.(), undefined);
+shouldThrowTypeError(() => ({})?.['i'](), '(intermediate value)["i"] is not a function');
+shouldBe(({})['i']?.(), undefined);
+shouldBe(({})?.['i']?.(), undefined);
+
+shouldThrowTypeError(() => ({})?.a['b'], 'can\'t access property "b", (intermediate value).a is undefined');
+shouldBe(({})?.a?.['b'], undefined);
+shouldBe(null?.a['b']().c, undefined);
+shouldThrowTypeError(() => ({})?.['a'].b, 'can\'t access property "b", (intermediate value)["a"] is undefined');
+shouldBe(({})?.['a']?.b, undefined);
+shouldBe(null?.['a'].b()['c'], undefined);
+shouldBe(null?.()().a['b'], undefined);
+
+const o0 = { a: { b() { return this._b.bind(this); }, _b() { return this.__b; }, __b: { c: 42 } } };
+shouldBe(o0?.a?.['b']?.()?.()?.c, 42);
+shouldBe(o0?.i?.['j']?.()?.()?.k, undefined);
+shouldBe((o0.a?._b)?.().c, 42);
+shouldBe((o0.a?._b)().c, 42);
+shouldBe((o0.a?.b?.())?.().c, 42);
+shouldBe((o0.a?.['b']?.())?.().c, 42);
+
+shouldBe(({ undefined: 3 })?.[null?.a], 3);
+shouldBe((() => 3)?.(null?.a), 3);
+
+const o1 = { count: 0, get x() { this.count++; return () => {}; } };
+o1.x?.y;
+shouldBe(o1.count, 1);
+o1.x?.['y'];
+shouldBe(o1.count, 2);
+o1.x?.();
+shouldBe(o1.count, 3);
+null?.(o1.x);
+shouldBe(o1.count, 3);
+
+shouldBe(delete undefined?.foo, true);
+shouldBe(delete null?.foo, true);
+shouldBe(delete undefined?.['foo'], true);
+shouldBe(delete null?.['foo'], true);
+shouldBe(delete undefined?.(), true);
+shouldBe(delete null?.(), true);
+shouldBe(delete ({}).a?.b?.b, true);
+shouldBe(delete ({a : {b: undefined}}).a?.b?.b, true);
+shouldBe(delete ({a : {b: undefined}}).a?.["b"]?.["b"], true);
+
+const o2 = { x: 0, y: 0, z() {} };
+shouldBe(delete o2?.x, true);
+shouldBe(o2.x, undefined);
+shouldBe(o2.y, 0);
+shouldBe(delete o2?.x, true);
+shouldBe(delete o2?.['y'], true);
+shouldBe(o2.y, undefined);
+shouldBe(delete o2?.['y'], true);
+shouldBe(delete o2.z?.(), true);
+
+function greet(name) { return `hey, ${name}${this.suffix ?? '.'}`; }
+shouldBe(eval?.('greet("world")'), 'hey, world.');
+shouldBe(greet?.call({ suffix: '!' }, 'world'), 'hey, world!');
+shouldBe(greet.call?.({ suffix: '!' }, 'world'), 'hey, world!');
+shouldBe(null?.call({ suffix: '!' }, 'world'), undefined);
+shouldBe(({}).call?.({ suffix: '!' }, 'world'), undefined);
+shouldBe(greet?.apply({ suffix: '?' }, ['world']), 'hey, world?');
+shouldBe(greet.apply?.({ suffix: '?' }, ['world']), 'hey, world?');
+shouldBe(null?.apply({ suffix: '?' }, ['world']), undefined);
+shouldBe(({}).apply?.({ suffix: '?' }, ['world']), undefined);
+shouldThrowSyntaxError('class C {} class D extends C { foo() { return super?.bar; } }');
+shouldThrowSyntaxError('class C {} class D extends C { foo() { return super?.["bar"]; } }');
+shouldThrowSyntaxError('class C {} class D extends C { constructor() { super?.(); } }');
+shouldThrowSyntaxError('const o = { C: class {} }; new o?.C();')
+shouldThrowSyntaxError('const o = { C: class {} }; new o?.["C"]();')
+shouldThrowSyntaxError('class C {} new C?.();')
+shouldThrowSyntaxError('function foo() { new?.target; }');
+shouldThrowSyntaxError('function tag() {} tag?.``;');
+shouldThrowSyntaxError('const o = { tag() {} }; o?.tag``;');
+
+// NOT an optional chain
+shouldBe(false?.4:5, 5);
+
+function testSideEffectCountFunction() {
+ let count = 0;
+ let a = {
+ b: {
+ c: {
+ d: () => {
+ count++;
+ return a;
+ }
+ }
+ }
+ }
+
+ a.b.c.d?.()?.b?.c?.d
+
+ shouldBe(count, 1);
+}
+
+function testSideEffectCountGetters() {
+ let count = 0;
+ let a = {
+ get b() {
+ count++;
+ return { c: {} };
+ }
+ }
+
+ a.b?.c?.d;
+ shouldBe(count, 1);
+ a.b?.c?.d;
+ shouldBe(count, 2);
+}
+
+testSideEffectCountFunction();
+testSideEffectCountGetters();
+
+// stress test SM
+shouldBe(({a : {b: undefined}}).a.b?.()()(), undefined);
+shouldBe(({a : {b: undefined}}).a.b?.()?.()(), undefined);
+shouldBe(({a : {b: () => undefined}}).a.b?.()?.(), undefined);
+shouldThrowTypeError(() => delete ({a : {b: undefined}}).a?.b.b.c, 'can\'t access property "b", (intermediate value).a.b is undefined');
+shouldBe(delete ({a : {b: undefined}}).a?.["b"]?.["b"], true);
+shouldThrowTypeError(() => (({a : {b: () => undefined}}).a.b?.())(), 'undefined is not a function');
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
+
+print("Tests complete");
diff --git a/js/src/tests/non262/expressions/shell.js b/js/src/tests/non262/expressions/shell.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/non262/expressions/shell.js
diff --git a/js/src/tests/non262/shell.js b/js/src/tests/non262/shell.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/non262/shell.js
diff --git a/js/src/tests/test262/language/expressions/assignment/dstr/array-elem-nested-memberexpr-optchain-prop-ref-init.js b/js/src/tests/test262/language/expressions/assignment/dstr/array-elem-nested-memberexpr-optchain-prop-ref-init.js
new file mode 100644
index 0000000000..8bdeca68e9
--- /dev/null
+++ b/js/src/tests/test262/language/expressions/assignment/dstr/array-elem-nested-memberexpr-optchain-prop-ref-init.js
@@ -0,0 +1,57 @@
+// |reftest| error:SyntaxError
+// This file was procedurally generated from the following sources:
+// - src/dstr-assignment/array-elem-nested-memberexpr-optchain-prop-ref-init.case
+// - src/dstr-assignment/syntax/assignment-expr.template
+/*---
+description: It is a Syntax Error if LeftHandSideExpression of an DestructuringAssignmentTarget is neither an ObjectLiteral nor an ArrayLiteral and AssignmentTargetType(LeftHandSideExpression) is not simple Using Object (MemberExpression OptionalChain .IdentifierName Initializer) (AssignmentExpression)
+esid: sec-variable-statement-runtime-semantics-evaluation
+features: [optional-chaining, destructuring-binding]
+flags: [generated]
+negative:
+ phase: parse
+ type: SyntaxError
+info: |
+ VariableDeclaration : BindingPattern Initializer
+
+ 1. Let rhs be the result of evaluating Initializer.
+ 2. Let rval be GetValue(rhs).
+ 3. ReturnIfAbrupt(rval).
+ 4. Return the result of performing BindingInitialization for
+ BindingPattern passing rval and undefined as arguments.
+
+ Syntax
+
+ AssignmentElement : DestructuringAssignmentTarget Initializer_opt
+ DestructuringAssignmentTarget : LeftHandSideExpression
+
+ Static Semantics: Early Errors
+
+ OptionalExpression:
+ MemberExpression OptionalChain
+ CallExpression OptionalChain
+ OptionalExpression OptionalChain
+
+ OptionalChain:
+ ?. [ Expression ]
+ ?. IdentifierName
+ ?. Arguments
+ ?. TemplateLiteral
+ OptionalChain [ Expression ]
+ OptionalChain .IdentifierName
+ OptionalChain Arguments
+ OptionalChain TemplateLiteral
+
+ DestructuringAssignmentTarget : LeftHandSideExpression
+
+ - It is a Syntax Error if LeftHandSideExpression is neither an ObjectLiteral nor an ArrayLiteral and IsValidSimpleAssignmentTarget(LeftHandSideExpression) is not true.
+
+ Static Semantics: IsValidSimpleAssignmentTarget
+
+ LeftHandSideExpression : OptionalExpression
+ 1. Return false.
+
+---*/
+$DONOTEVALUATE();
+var x = {};
+
+0, [x?.y = 42] = [23];
diff --git a/js/src/tests/test262/language/expressions/assignment/dstr/array-elem-put-obj-literal-optchain-prop-ref-init.js b/js/src/tests/test262/language/expressions/assignment/dstr/array-elem-put-obj-literal-optchain-prop-ref-init.js
new file mode 100644
index 0000000000..57d80fa31d
--- /dev/null
+++ b/js/src/tests/test262/language/expressions/assignment/dstr/array-elem-put-obj-literal-optchain-prop-ref-init.js
@@ -0,0 +1,60 @@
+// |reftest| error:SyntaxError
+// This file was procedurally generated from the following sources:
+// - src/dstr-assignment/array-elem-put-obj-literal-optchain-prop-ref-init.case
+// - src/dstr-assignment/syntax/assignment-expr.template
+/*---
+description: It is a Syntax Error if LeftHandSideExpression of an DestructuringAssignmentTarget is neither an ObjectLiteral nor an ArrayLiteral and AssignmentTargetType(LeftHandSideExpression) is not simple Using Object (AssignmentExpression)
+esid: sec-variable-statement-runtime-semantics-evaluation
+features: [optional-chaining, destructuring-binding]
+flags: [generated]
+negative:
+ phase: parse
+ type: SyntaxError
+info: |
+ VariableDeclaration : BindingPattern Initializer
+
+ 1. Let rhs be the result of evaluating Initializer.
+ 2. Let rval be GetValue(rhs).
+ 3. ReturnIfAbrupt(rval).
+ 4. Return the result of performing BindingInitialization for
+ BindingPattern passing rval and undefined as arguments.
+
+ Syntax
+
+ AssignmentElement : DestructuringAssignmentTarget Initializer_opt
+ DestructuringAssignmentTarget : LeftHandSideExpression
+
+ Static Semantics: Early Errors
+
+ OptionalExpression:
+ MemberExpression OptionalChain
+ CallExpression OptionalChain
+ OptionalExpression OptionalChain
+
+ OptionalChain:
+ ?. [ Expression ]
+ ?. IdentifierName
+ ?. Arguments
+ ?. TemplateLiteral
+ OptionalChain [ Expression ]
+ OptionalChain .IdentifierName
+ OptionalChain Arguments
+ OptionalChain TemplateLiteral
+
+ DestructuringAssignmentTarget : LeftHandSideExpression
+
+ - It is a Syntax Error if LeftHandSideExpression is neither an ObjectLiteral nor an ArrayLiteral and IsValidSimpleAssignmentTarget(LeftHandSideExpression) is not true.
+
+ Static Semantics: IsValidSimpleAssignmentTarget
+
+ LeftHandSideExpression : OptionalExpression
+ 1. Return false.
+
+---*/
+$DONOTEVALUATE();
+
+0, [{
+ set y(val) {
+ throw new Test262Error('The property should not be accessed.');
+ }
+}?.y = 42] = [23];
diff --git a/js/src/tests/test262/language/expressions/assignment/dstr/obj-prop-elem-target-memberexpr-optchain-prop-ref-init.js b/js/src/tests/test262/language/expressions/assignment/dstr/obj-prop-elem-target-memberexpr-optchain-prop-ref-init.js
new file mode 100644
index 0000000000..b186432078
--- /dev/null
+++ b/js/src/tests/test262/language/expressions/assignment/dstr/obj-prop-elem-target-memberexpr-optchain-prop-ref-init.js
@@ -0,0 +1,57 @@
+// |reftest| error:SyntaxError
+// This file was procedurally generated from the following sources:
+// - src/dstr-assignment/obj-prop-elem-target-memberexpr-optchain-prop-ref-init.case
+// - src/dstr-assignment/syntax/assignment-expr.template
+/*---
+description: It is a Syntax Error if LeftHandSideExpression of an DestructuringAssignmentTarget is neither an ObjectLiteral nor an ArrayLiteral and AssignmentTargetType(LeftHandSideExpression) is not simple Using Object (MemberExpression OptionalChain .IdentifierName Initializer) (AssignmentExpression)
+esid: sec-variable-statement-runtime-semantics-evaluation
+features: [optional-chaining, destructuring-binding]
+flags: [generated]
+negative:
+ phase: parse
+ type: SyntaxError
+info: |
+ VariableDeclaration : BindingPattern Initializer
+
+ 1. Let rhs be the result of evaluating Initializer.
+ 2. Let rval be GetValue(rhs).
+ 3. ReturnIfAbrupt(rval).
+ 4. Return the result of performing BindingInitialization for
+ BindingPattern passing rval and undefined as arguments.
+
+ Syntax
+
+ AssignmentElement : DestructuringAssignmentTarget Initializer_opt
+ DestructuringAssignmentTarget : LeftHandSideExpression
+
+ Static Semantics: Early Errors
+
+ OptionalExpression:
+ MemberExpression OptionalChain
+ CallExpression OptionalChain
+ OptionalExpression OptionalChain
+
+ OptionalChain:
+ ?. [ Expression ]
+ ?. IdentifierName
+ ?. Arguments
+ ?. TemplateLiteral
+ OptionalChain [ Expression ]
+ OptionalChain .IdentifierName
+ OptionalChain Arguments
+ OptionalChain TemplateLiteral
+
+ DestructuringAssignmentTarget : LeftHandSideExpression
+
+ - It is a Syntax Error if LeftHandSideExpression is neither an ObjectLiteral nor an ArrayLiteral and IsValidSimpleAssignmentTarget(LeftHandSideExpression) is not true.
+
+ Static Semantics: IsValidSimpleAssignmentTarget
+
+ LeftHandSideExpression : OptionalExpression
+ 1. Return false.
+
+---*/
+$DONOTEVALUATE();
+var y = {};
+
+0, { x: y?.z = 42 } = { x: 23 };
diff --git a/js/src/tests/test262/language/expressions/assignment/dstr/obj-prop-elem-target-obj-literal-optchain-prop-ref-init.js b/js/src/tests/test262/language/expressions/assignment/dstr/obj-prop-elem-target-obj-literal-optchain-prop-ref-init.js
new file mode 100644
index 0000000000..d0b80f742e
--- /dev/null
+++ b/js/src/tests/test262/language/expressions/assignment/dstr/obj-prop-elem-target-obj-literal-optchain-prop-ref-init.js
@@ -0,0 +1,60 @@
+// |reftest| error:SyntaxError
+// This file was procedurally generated from the following sources:
+// - src/dstr-assignment/obj-prop-elem-target-obj-literal-optchain-prop-ref-init.case
+// - src/dstr-assignment/syntax/assignment-expr.template
+/*---
+description: It is a Syntax Error if LeftHandSideExpression of an DestructuringAssignmentTarget is neither an ObjectLiteral nor an ArrayLiteral and AssignmentTargetType(LeftHandSideExpression) is not simple Using Object (AssignmentExpression)
+esid: sec-variable-statement-runtime-semantics-evaluation
+features: [optional-chaining, destructuring-binding]
+flags: [generated]
+negative:
+ phase: parse
+ type: SyntaxError
+info: |
+ VariableDeclaration : BindingPattern Initializer
+
+ 1. Let rhs be the result of evaluating Initializer.
+ 2. Let rval be GetValue(rhs).
+ 3. ReturnIfAbrupt(rval).
+ 4. Return the result of performing BindingInitialization for
+ BindingPattern passing rval and undefined as arguments.
+
+ Syntax
+
+ AssignmentElement : DestructuringAssignmentTarget Initializer_opt
+ DestructuringAssignmentTarget : LeftHandSideExpression
+
+ Static Semantics: Early Errors
+
+ OptionalExpression:
+ MemberExpression OptionalChain
+ CallExpression OptionalChain
+ OptionalExpression OptionalChain
+
+ OptionalChain:
+ ?. [ Expression ]
+ ?. IdentifierName
+ ?. Arguments
+ ?. TemplateLiteral
+ OptionalChain [ Expression ]
+ OptionalChain .IdentifierName
+ OptionalChain Arguments
+ OptionalChain TemplateLiteral
+
+ DestructuringAssignmentTarget : LeftHandSideExpression
+
+ - It is a Syntax Error if LeftHandSideExpression is neither an ObjectLiteral nor an ArrayLiteral and IsValidSimpleAssignmentTarget(LeftHandSideExpression) is not true.
+
+ Static Semantics: IsValidSimpleAssignmentTarget
+
+ LeftHandSideExpression : OptionalExpression
+ 1. Return false.
+
+---*/
+$DONOTEVALUATE();
+
+0, { x: {
+ set y(val) {
+ throw new Test262Error('The property should not be accessed.');
+ }
+}?.y = 42} = {x: 42};
diff --git a/js/src/tests/test262/language/expressions/assignment/dstr/shell.js b/js/src/tests/test262/language/expressions/assignment/dstr/shell.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/language/expressions/assignment/dstr/shell.js
diff --git a/js/src/tests/test262/language/expressions/assignment/shell.js b/js/src/tests/test262/language/expressions/assignment/shell.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/language/expressions/assignment/shell.js
diff --git a/js/src/tests/test262/language/expressions/shell.js b/js/src/tests/test262/language/expressions/shell.js
new file mode 100644
index 0000000000..9192cb7bf3
--- /dev/null
+++ b/js/src/tests/test262/language/expressions/shell.js
@@ -0,0 +1,16 @@
+// GENERATED, DO NOT EDIT
+// file: tcoHelper.js
+// Copyright (C) 2016 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+description: |
+ This defines the number of consecutive recursive function calls that must be
+ made in order to prove that stack frames are properly destroyed according to
+ ES2015 tail call optimization semantics.
+defines: [$MAX_ITERATIONS]
+---*/
+
+
+
+
+var $MAX_ITERATIONS = 100000; \ No newline at end of file
diff --git a/js/src/tests/test262/language/optional-chaining/call-expression-super-no-base.js b/js/src/tests/test262/language/optional-chaining/call-expression-super-no-base.js
new file mode 100644
index 0000000000..da3a634bdf
--- /dev/null
+++ b/js/src/tests/test262/language/optional-chaining/call-expression-super-no-base.js
@@ -0,0 +1,24 @@
+// |reftest| error:SyntaxError
+// Copyright 2019 Google, Inc. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: prod-OptionalExpression
+description: >
+ should not suppress error if super called on class with no base
+info: |
+ Left-Hand-Side Expressions
+ OptionalExpression:
+ SuperCall OptionalChain
+features: [optional-chaining]
+negative:
+ phase: parse
+ type: SyntaxError
+---*/
+
+$DONOTEVALUATE();
+
+class C {
+ constructor () {
+ super()?.a;
+ }
+}
diff --git a/js/src/tests/test262/language/optional-chaining/call-expression.js b/js/src/tests/test262/language/optional-chaining/call-expression.js
new file mode 100644
index 0000000000..aa3f4abeb5
--- /dev/null
+++ b/js/src/tests/test262/language/optional-chaining/call-expression.js
@@ -0,0 +1,77 @@
+// Copyright 2019 Google, Inc. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: prod-OptionalExpression
+description: >
+ optional chain on call expression
+info: |
+ Left-Hand-Side Expressions
+ OptionalExpression:
+ CallExpression OptionalChain
+features: [optional-chaining]
+---*/
+
+// CallExpression CoverCallExpressionAndAsyncArrowHead
+function fn () {
+ return {a: 33};
+};
+const obj = {
+ fn () {
+ return 44;
+ }
+}
+assert.sameValue(33, fn()?.a);
+assert.sameValue(undefined, fn()?.b);
+assert.sameValue(44, obj?.fn());
+
+// CallExpression SuperCall
+class A {}
+class B extends A {
+ constructor () {
+ assert.sameValue(undefined, super()?.a);
+ }
+}
+new B();
+
+// CallExpression Arguments
+function fn2 () {
+ return () => {
+ return {a: 66};
+ };
+}
+function fn3 () {
+ return () => {
+ return null;
+ };
+}
+assert.sameValue(66, fn2()()?.a);
+assert.sameValue(undefined, fn3()()?.a);
+
+// CallExpression [Expression]
+function fn4 () {
+ return [{a: 77}];
+}
+function fn5 () {
+ return [];
+}
+assert.sameValue(77, fn4()[0]?.a);
+assert.sameValue(undefined, fn5()[0]?.a);
+
+// CallExpression .IdentifierName
+function fn6 () {
+ return {
+ a: {
+ b: 88
+ }
+ };
+}
+assert.sameValue(88, fn6().a?.b);
+assert.sameValue(undefined, fn6().b?.c);
+
+// CallExpression TemplateLiteral
+function fn7 () {
+ return () => {};
+}
+assert.sameValue(undefined, fn7()`hello`?.a);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/language/optional-chaining/early-errors-tail-position-null-op-template-string-esi.js b/js/src/tests/test262/language/optional-chaining/early-errors-tail-position-null-op-template-string-esi.js
new file mode 100644
index 0000000000..ae830b1300
--- /dev/null
+++ b/js/src/tests/test262/language/optional-chaining/early-errors-tail-position-null-op-template-string-esi.js
@@ -0,0 +1,26 @@
+// |reftest| error:SyntaxError
+// Copyright 2020 Salesforce.com, Inc. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: prod-OptionalExpression
+description: >
+ template string passed to tail position of optional chain
+info: |
+ Static Semantics: Early Errors
+ OptionalChain:
+ ?.TemplateLiteral
+ OptionalChain TemplateLiteral
+
+ It is a Syntax Error if any code matches this production.
+features: [optional-chaining]
+negative:
+ phase: parse
+ type: SyntaxError
+---*/
+
+$DONOTEVALUATE();
+
+// This production exists in order to prevent automatic semicolon
+// insertion rules.
+null?.
+ `hello`
diff --git a/js/src/tests/test262/language/optional-chaining/early-errors-tail-position-null-op-template-string.js b/js/src/tests/test262/language/optional-chaining/early-errors-tail-position-null-op-template-string.js
new file mode 100644
index 0000000000..cb8361cd0c
--- /dev/null
+++ b/js/src/tests/test262/language/optional-chaining/early-errors-tail-position-null-op-template-string.js
@@ -0,0 +1,23 @@
+// |reftest| error:SyntaxError
+// Copyright 2020 Salesforce.com, Inc. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: prod-OptionalExpression
+description: >
+ template string passed to tail position of optional chain
+info: |
+ Static Semantics: Early Errors
+ OptionalChain:
+ ?.TemplateLiteral
+ OptionalChain TemplateLiteral
+
+ It is a Syntax Error if any code matches this production.
+features: [optional-chaining]
+negative:
+ phase: parse
+ type: SyntaxError
+---*/
+
+$DONOTEVALUATE();
+
+null?.`hello`;
diff --git a/js/src/tests/test262/language/optional-chaining/early-errors-tail-position-null-optchain-template-string-esi.js b/js/src/tests/test262/language/optional-chaining/early-errors-tail-position-null-optchain-template-string-esi.js
new file mode 100644
index 0000000000..9c992b00d4
--- /dev/null
+++ b/js/src/tests/test262/language/optional-chaining/early-errors-tail-position-null-optchain-template-string-esi.js
@@ -0,0 +1,26 @@
+// |reftest| error:SyntaxError
+// Copyright 2020 Salesforce.com, Inc. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: prod-OptionalExpression
+description: >
+ template string passed to tail position of optional chain
+info: |
+ Static Semantics: Early Errors
+ OptionalChain:
+ ?.TemplateLiteral
+ OptionalChain TemplateLiteral
+
+ It is a Syntax Error if any code matches this production.
+features: [optional-chaining]
+negative:
+ phase: parse
+ type: SyntaxError
+---*/
+
+$DONOTEVALUATE();
+
+// This production exists in order to prevent automatic semicolon
+// insertion rules.
+null?.fn
+ `hello`
diff --git a/js/src/tests/test262/language/optional-chaining/early-errors-tail-position-null-optchain-template-string.js b/js/src/tests/test262/language/optional-chaining/early-errors-tail-position-null-optchain-template-string.js
new file mode 100644
index 0000000000..a74ca1cf32
--- /dev/null
+++ b/js/src/tests/test262/language/optional-chaining/early-errors-tail-position-null-optchain-template-string.js
@@ -0,0 +1,23 @@
+// |reftest| error:SyntaxError
+// Copyright 2020 Salesforce.com, Inc. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: prod-OptionalExpression
+description: >
+ template string passed to tail position of optional chain
+info: |
+ Static Semantics: Early Errors
+ OptionalChain:
+ ?.TemplateLiteral
+ OptionalChain TemplateLiteral
+
+ It is a Syntax Error if any code matches this production.
+features: [optional-chaining]
+negative:
+ phase: parse
+ type: SyntaxError
+---*/
+
+$DONOTEVALUATE();
+
+null?.fn`hello`;
diff --git a/js/src/tests/test262/language/optional-chaining/early-errors-tail-position-op-template-string-esi.js b/js/src/tests/test262/language/optional-chaining/early-errors-tail-position-op-template-string-esi.js
new file mode 100644
index 0000000000..c1ec6d707d
--- /dev/null
+++ b/js/src/tests/test262/language/optional-chaining/early-errors-tail-position-op-template-string-esi.js
@@ -0,0 +1,28 @@
+// |reftest| error:SyntaxError
+// Copyright 2020 Salesforce.com, Inc. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: prod-OptionalExpression
+description: >
+ template string passed to tail position of optional chain
+info: |
+ Static Semantics: Early Errors
+ OptionalChain:
+ ?.TemplateLiteral
+ OptionalChain TemplateLiteral
+
+ It is a Syntax Error if any code matches this production.
+features: [optional-chaining]
+negative:
+ phase: parse
+ type: SyntaxError
+---*/
+
+$DONOTEVALUATE();
+
+const a = function() {};
+
+// This production exists in order to prevent automatic semicolon
+// insertion rules.
+a?.
+ `hello`
diff --git a/js/src/tests/test262/language/optional-chaining/early-errors-tail-position-op-template-string.js b/js/src/tests/test262/language/optional-chaining/early-errors-tail-position-op-template-string.js
new file mode 100644
index 0000000000..043bfb3da3
--- /dev/null
+++ b/js/src/tests/test262/language/optional-chaining/early-errors-tail-position-op-template-string.js
@@ -0,0 +1,25 @@
+// |reftest| error:SyntaxError
+// Copyright 2020 Salesforce.com, Inc. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: prod-OptionalExpression
+description: >
+ template string passed to tail position of optional chain
+info: |
+ Static Semantics: Early Errors
+ OptionalChain:
+ ?.TemplateLiteral
+ OptionalChain TemplateLiteral
+
+ It is a Syntax Error if any code matches this production.
+features: [optional-chaining]
+negative:
+ phase: parse
+ type: SyntaxError
+---*/
+
+$DONOTEVALUATE();
+
+const a = function() {};
+
+a?.`hello`;
diff --git a/js/src/tests/test262/language/optional-chaining/early-errors-tail-position-optchain-template-string-esi.js b/js/src/tests/test262/language/optional-chaining/early-errors-tail-position-optchain-template-string-esi.js
new file mode 100644
index 0000000000..1aefaaec22
--- /dev/null
+++ b/js/src/tests/test262/language/optional-chaining/early-errors-tail-position-optchain-template-string-esi.js
@@ -0,0 +1,28 @@
+// |reftest| error:SyntaxError
+// Copyright 2019 Google, Inc. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: prod-OptionalExpression
+description: >
+ template string passed to tail position of optional chain
+info: |
+ Static Semantics: Early Errors
+ OptionalChain:
+ ?.TemplateLiteral
+ OptionalChain TemplateLiteral
+
+ It is a Syntax Error if any code matches this production.
+features: [optional-chaining]
+negative:
+ phase: parse
+ type: SyntaxError
+---*/
+
+$DONOTEVALUATE();
+
+const a = {fn() {}};
+
+// This production exists in order to prevent automatic semicolon
+// insertion rules.
+a?.fn
+ `hello`
diff --git a/js/src/tests/test262/language/optional-chaining/early-errors-tail-position-optchain-template-string.js b/js/src/tests/test262/language/optional-chaining/early-errors-tail-position-optchain-template-string.js
new file mode 100644
index 0000000000..277048e1aa
--- /dev/null
+++ b/js/src/tests/test262/language/optional-chaining/early-errors-tail-position-optchain-template-string.js
@@ -0,0 +1,25 @@
+// |reftest| error:SyntaxError
+// Copyright 2019 Google, Inc. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: prod-OptionalExpression
+description: >
+ template string passed to tail position of optional chain
+info: |
+ Static Semantics: Early Errors
+ OptionalChain:
+ ?.TemplateLiteral
+ OptionalChain TemplateLiteral
+
+ It is a Syntax Error if any code matches this production.
+features: [optional-chaining]
+negative:
+ phase: parse
+ type: SyntaxError
+---*/
+
+$DONOTEVALUATE();
+
+const a = {fn() {}};
+
+a?.fn`hello`;
diff --git a/js/src/tests/test262/language/optional-chaining/eval-optional-call.js b/js/src/tests/test262/language/optional-chaining/eval-optional-call.js
new file mode 100644
index 0000000000..8ff4800560
--- /dev/null
+++ b/js/src/tests/test262/language/optional-chaining/eval-optional-call.js
@@ -0,0 +1,41 @@
+// Copyright 2020 Toru Nagashima. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-optional-chaining-chain-evaluation
+description: optional call invoked on eval function should be indirect eval.
+info: |
+ Runtime Semantics: ChainEvaluation
+ OptionalChain: ?. Arguments
+ 1. Let thisChain be this OptionalChain.
+ 2. Let tailCall be IsInTailPosition(thisChain).
+ 3. Return ? EvaluateCall(baseValue, baseReference, Arguments, tailCall).
+
+ Runtime Semantics: EvaluateCall ( func, ref, arguments, tailPosition )
+
+ ...
+ 7. Let result be Call(func, thisValue, argList).
+ ...
+
+ eval ( x )
+
+ ...
+ 4. Return ? PerformEval(x, callerRealm, false, false).
+
+ Runtime Semantics: PerformEval ( x, callerRealm, strictCaller, direct )
+features: [optional-chaining]
+---*/
+
+const a = 'global';
+
+function fn() {
+ const a = 'local';
+ return eval?.('a');
+}
+
+assert.sameValue(fn(), 'global', 'fn() returns "global" value from indirect eval');
+
+const b = (a => eval?.('a'))('local');
+
+assert.sameValue(b, 'global', 'b is "global", from indirect eval not observing parameter');
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/language/optional-chaining/iteration-statement-do.js b/js/src/tests/test262/language/optional-chaining/iteration-statement-do.js
new file mode 100644
index 0000000000..470f067b20
--- /dev/null
+++ b/js/src/tests/test262/language/optional-chaining/iteration-statement-do.js
@@ -0,0 +1,20 @@
+// Copyright 2019 Google, LLC. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: prod-OptionalExpression
+description: >
+ optional chain in test portion of do while statement
+info: |
+ IterationStatement
+ do Statement while (OptionalExpression)
+features: [optional-chaining]
+---*/
+let count = 0;
+const obj = {a: true};
+do {
+ count++;
+ break;
+} while (obj?.a);
+assert.sameValue(1, count);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/language/optional-chaining/iteration-statement-for-await-of.js b/js/src/tests/test262/language/optional-chaining/iteration-statement-for-await-of.js
new file mode 100644
index 0000000000..2f668fd36d
--- /dev/null
+++ b/js/src/tests/test262/language/optional-chaining/iteration-statement-for-await-of.js
@@ -0,0 +1,36 @@
+// |reftest| async
+// Copyright 2019 Google, LLC. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: prod-OptionalExpression
+description: >
+ optional chain RHS of for await statement
+info: |
+ IterationStatement
+ for await (LeftHandSideExpression of AssignmentExpression) Statement
+features: [optional-chaining]
+flags: [async]
+---*/
+const obj = {
+ iterable: {
+ [Symbol.asyncIterator]() {
+ return {
+ i: 0,
+ next() {
+ if (this.i < 3) {
+ return Promise.resolve({ value: this.i++, done: false });
+ }
+ return Promise.resolve({ done: true });
+ }
+ };
+ }
+ }
+};
+async function checkAssertions() {
+ let count = 0;
+ for await (const num of obj?.iterable) {
+ count += num;
+ }
+ assert.sameValue(3, count);
+}
+checkAssertions().then($DONE, $DONE);
diff --git a/js/src/tests/test262/language/optional-chaining/iteration-statement-for-in.js b/js/src/tests/test262/language/optional-chaining/iteration-statement-for-in.js
new file mode 100644
index 0000000000..6774675f1e
--- /dev/null
+++ b/js/src/tests/test262/language/optional-chaining/iteration-statement-for-in.js
@@ -0,0 +1,24 @@
+// Copyright 2019 Google, LLC. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: prod-OptionalExpression
+description: >
+ optional chain in test portion of do while statement
+info: |
+ IterationStatement
+ for (LeftHandSideExpression in Expression) Statement
+features: [optional-chaining]
+---*/
+const obj = {
+ inner: {
+ a: 1,
+ b: 2
+ }
+};
+let str = '';
+for (const key in obj?.inner) {
+ str += key;
+}
+assert.sameValue('ab', str);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/language/optional-chaining/iteration-statement-for-of-type-error.js b/js/src/tests/test262/language/optional-chaining/iteration-statement-for-of-type-error.js
new file mode 100644
index 0000000000..938e10d8d4
--- /dev/null
+++ b/js/src/tests/test262/language/optional-chaining/iteration-statement-for-of-type-error.js
@@ -0,0 +1,30 @@
+// Copyright 2019 Google, LLC. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: prod-OptionalExpression
+description: >
+ optional chain returning undefined in RHS of for of statement
+info: |
+ IterationStatement
+ for (LeftHandSideExpression of Expression) Statement
+features: [optional-chaining]
+---*/
+
+assert.throws(TypeError, function() {
+ for (const key of {}?.a) ;
+});
+
+assert.throws(TypeError, function() {
+ for (const key of {}?.a) {}
+});
+
+const obj = undefined;
+assert.throws(TypeError, function() {
+ for (const key of obj?.a) {}
+});
+
+assert.throws(TypeError, function() {
+ for (const key of obj?.a);
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/language/optional-chaining/iteration-statement-for.js b/js/src/tests/test262/language/optional-chaining/iteration-statement-for.js
new file mode 100644
index 0000000000..cb884d486e
--- /dev/null
+++ b/js/src/tests/test262/language/optional-chaining/iteration-statement-for.js
@@ -0,0 +1,45 @@
+// Copyright 2019 Google, LLC. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: prod-OptionalExpression
+description: >
+ optional chain in init/test/update of for statement
+info: |
+ IterationStatement
+ for (Expression; Expression; Expression) Statement
+features: [optional-chaining]
+---*/
+
+// OptionalExpression in test.
+let count;
+const obj = {a: true};
+for (count = 0; obj?.a; count++) {
+ if (count > 0) break;
+}
+assert.sameValue(count, 1);
+
+// OptionalExpression in init/test/update.
+let count2 = 0;
+const obj2 = undefined;
+
+for (obj?.a; obj2?.a; obj?.a) { count2++; }
+assert.sameValue(count2, 0);
+
+for (obj?.a; undefined?.a; obj?.a) { count2++; }
+assert.sameValue(count2, 0);
+
+// Short-circuiting
+let touched = 0;
+const obj3 = {
+ get a() {
+ count++;
+ return undefined; // explicit for clarity
+ }
+};
+for (count = 0; true; obj3?.a?.[touched++]) {
+ if (count > 0) { break; }
+}
+assert.sameValue(count, 1);
+assert.sameValue(touched, 0);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/language/optional-chaining/iteration-statement-while.js b/js/src/tests/test262/language/optional-chaining/iteration-statement-while.js
new file mode 100644
index 0000000000..1390315896
--- /dev/null
+++ b/js/src/tests/test262/language/optional-chaining/iteration-statement-while.js
@@ -0,0 +1,20 @@
+// Copyright 2019 Google, LLC. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: prod-OptionalExpression
+description: >
+ optional chain in test portion of while statement
+info: |
+ IterationStatement
+ while (Expression) Statement
+features: [optional-chaining]
+---*/
+let count = 0;
+const obj = {a: true};
+while (obj?.a) {
+ count++;
+ break;
+}
+assert.sameValue(1, count);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/language/optional-chaining/member-expression-async-identifier.js b/js/src/tests/test262/language/optional-chaining/member-expression-async-identifier.js
new file mode 100644
index 0000000000..a0abb209d2
--- /dev/null
+++ b/js/src/tests/test262/language/optional-chaining/member-expression-async-identifier.js
@@ -0,0 +1,33 @@
+// |reftest| async
+// Copyright 2019 Google, Inc. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: prod-OptionalExpression
+description: >
+ optional chain on member expression in async context
+info: |
+ Left-Hand-Side Expressions
+ OptionalExpression
+ MemberExpression [PrimaryExpression identifier] OptionalChain
+features: [optional-chaining]
+flags: [async]
+---*/
+
+const a = undefined;
+const c = {d: Promise.resolve(11)};
+async function checkAssertions() {
+ assert.sameValue(await a?.b, undefined);
+ assert.sameValue(await c?.d, 11);
+
+ Promise.prototype.x = 42;
+ var res = await Promise.resolve(undefined)?.x;
+ assert.sameValue(res, 42, 'await unwraps the evaluation of the whole optional chaining expression #1');
+
+ Promise.prototype.y = 43;
+ var res = await Promise.reject(undefined)?.y;
+ assert.sameValue(res, 43, 'await unwraps the evaluation of the whole optional chaining expression #2');
+
+ c.e = Promise.resolve(39);
+ assert.sameValue(await c?.e, 39, 'await unwraps the promise given after the evaluation of the OCE');
+}
+checkAssertions().then($DONE, $DONE);
diff --git a/js/src/tests/test262/language/optional-chaining/member-expression-async-literal.js b/js/src/tests/test262/language/optional-chaining/member-expression-async-literal.js
new file mode 100644
index 0000000000..4bdeb447dc
--- /dev/null
+++ b/js/src/tests/test262/language/optional-chaining/member-expression-async-literal.js
@@ -0,0 +1,20 @@
+// |reftest| async
+// Copyright 2019 Google, Inc. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: prod-OptionalExpression
+description: >
+ optional chain on member expression in async context
+info: |
+ Left-Hand-Side Expressions
+ OptionalExpression:
+ MemberExpression [PrimaryExpression literal] OptionalChain
+features: [optional-chaining]
+flags: [async]
+---*/
+
+async function checkAssertions() {
+ assert.sameValue(await "hello"?.[0], 'h');
+ assert.sameValue(await null?.a, undefined);
+}
+checkAssertions().then($DONE, $DONE);
diff --git a/js/src/tests/test262/language/optional-chaining/member-expression-async-this.js b/js/src/tests/test262/language/optional-chaining/member-expression-async-this.js
new file mode 100644
index 0000000000..5de87fa9bb
--- /dev/null
+++ b/js/src/tests/test262/language/optional-chaining/member-expression-async-this.js
@@ -0,0 +1,21 @@
+// |reftest| async
+// Copyright 2019 Google, Inc. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: prod-OptionalExpression
+description: >
+ optional chain on member expression in async context
+info: |
+ Left-Hand-Side Expressions
+ OptionalExpression:
+ MemberExpression [PrimaryExpression this] OptionalChain
+features: [optional-chaining]
+flags: [async]
+---*/
+
+async function thisFn() {
+ return await this?.a
+}
+thisFn.call({a: Promise.resolve(33)}).then(function(arg) {
+ assert.sameValue(33, arg);
+}).then($DONE, $DONE);
diff --git a/js/src/tests/test262/language/optional-chaining/member-expression.js b/js/src/tests/test262/language/optional-chaining/member-expression.js
new file mode 100644
index 0000000000..4854182c75
--- /dev/null
+++ b/js/src/tests/test262/language/optional-chaining/member-expression.js
@@ -0,0 +1,106 @@
+// Copyright 2019 Google, Inc. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: prod-OptionalExpression
+description: >
+ optional chain on member expression
+info: |
+ Left-Hand-Side Expressions
+ OptionalExpression:
+ MemberExpression OptionalChain
+features: [optional-chaining]
+---*/
+
+// PrimaryExpression
+// IdentifierReference
+const a = {b: 22};
+assert.sameValue(22, a?.b);
+// this
+function fn () {
+ return this?.a
+}
+assert.sameValue(33, fn.call({a: 33}));
+// Literal
+assert.sameValue(undefined, "hello"?.a);
+assert.sameValue(undefined, null?.a);
+// ArrayLiteral
+assert.sameValue(2, [1, 2]?.[1]);
+// ObjectLiteral
+assert.sameValue(44, {a: 44}?.a);
+// FunctionExpression
+assert.sameValue('a', (function a () {}?.name));
+// ClassExpression
+assert.sameValue('Foo', (class Foo {}?.name));
+// GeneratorFunction
+assert.sameValue('a', (function * a () {}?.name));
+// AsyncFunctionExpression
+assert.sameValue('a', (async function a () {}?.name));
+// AsyncGeneratorExpression
+assert.sameValue('a', (async function * a () {}?.name));
+// RegularExpressionLiteral
+assert.sameValue(true, /[a-z]/?.test('a'));
+// TemplateLiteral
+assert.sameValue('h', `hello`?.[0]);
+// CoverParenthesizedExpressionAndArrowParameterList
+assert.sameValue(undefined, ({a: 33}, null)?.a);
+assert.sameValue(33, (undefined, {a: 33})?.a);
+
+// MemberExpression [ Expression ]
+const arr = [{a: 33}];
+assert.sameValue(33, arr[0]?.a);
+assert.sameValue(undefined, arr[1]?.a);
+
+// MemberExpression .IdentifierName
+const obj = {a: {b: 44}};
+assert.sameValue(44, obj.a?.b);
+assert.sameValue(undefined, obj.c?.b);
+
+// MemberExpression TemplateLiteral
+function f2 () {
+ return {a: 33};
+}
+function f3 () {}
+assert.sameValue(33, f2`hello world`?.a);
+assert.sameValue(undefined, f3`hello world`?.a);
+
+// MemberExpression SuperProperty
+class A {
+ a () {}
+ undf () {
+ return super.a?.c;
+ }
+}
+class B extends A {
+ dot () {
+ return super.a?.name;
+ }
+ expr () {
+ return super['a']?.name;
+ }
+ undf2 () {
+ return super.b?.c;
+ }
+}
+const subcls = new B();
+assert.sameValue('a', subcls.dot());
+assert.sameValue('a', subcls.expr());
+assert.sameValue(undefined, subcls.undf2());
+assert.sameValue(undefined, (new A()).undf());
+
+// MemberExpression MetaProperty
+class C {
+ constructor () {
+ assert.sameValue(undefined, new.target?.a);
+ }
+}
+new C();
+
+// new MemberExpression Arguments
+class D {
+ constructor (val) {
+ this.a = val;
+ }
+}
+assert.sameValue(99, new D(99)?.a);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/language/optional-chaining/new-target-optional-call.js b/js/src/tests/test262/language/optional-chaining/new-target-optional-call.js
new file mode 100644
index 0000000000..df05a11507
--- /dev/null
+++ b/js/src/tests/test262/language/optional-chaining/new-target-optional-call.js
@@ -0,0 +1,32 @@
+// Copyright 2019 Google, LLC. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: prod-OptionalExpression
+description: >
+ optional call invoked on new.target should be equivalent to call
+info: |
+ OptionalExpression
+ MemberExpression OptionalChain
+ NewTarget OptionalChain
+features: [optional-chaining]
+---*/
+
+const newTargetContext = (function() { return this; })();
+
+let called = false;
+// should be set to 'undefined' or global context, depending on whether
+// mode is strict or sloppy.
+let context = null;
+function Base() {
+ called = true;
+ context = this;
+}
+function Foo(blerg) {
+ new.target?.();
+}
+
+Reflect.construct(Foo, [], Base);
+assert(context === newTargetContext);
+assert.sameValue(called, true);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/language/optional-chaining/optional-call-preserves-this.js b/js/src/tests/test262/language/optional-chaining/optional-call-preserves-this.js
new file mode 100644
index 0000000000..dbaf92c3b9
--- /dev/null
+++ b/js/src/tests/test262/language/optional-chaining/optional-call-preserves-this.js
@@ -0,0 +1,29 @@
+// Copyright (C) 2019 Sony Interactive Entertainment Inc. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-optional-chaining-chain-evaluation
+description: >
+ optional call must preserve this context, as with a non-optional call
+info: |
+ OptionalChain : ?. Arguments
+ 1. Let thisChain be this OptionalChain.
+ 2. Let tailCall be IsInTailPosition(thisChain).
+ 3. Return ? EvaluateCall(baseValue, baseReference, Arguments, tailCall).
+features: [optional-chaining]
+---*/
+
+const a = {
+ b() { return this._b; },
+ _b: { c: 42 }
+};
+
+assert.sameValue(a?.b().c, 42);
+assert.sameValue((a?.b)().c, 42);
+
+assert.sameValue(a.b?.().c, 42);
+assert.sameValue((a.b)?.().c, 42);
+
+assert.sameValue(a?.b?.().c, 42);
+assert.sameValue((a?.b)?.().c, 42);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/language/optional-chaining/optional-chain-async-optional-chain-square-brackets.js b/js/src/tests/test262/language/optional-chaining/optional-chain-async-optional-chain-square-brackets.js
new file mode 100644
index 0000000000..b47b2aeeed
--- /dev/null
+++ b/js/src/tests/test262/language/optional-chaining/optional-chain-async-optional-chain-square-brackets.js
@@ -0,0 +1,29 @@
+// |reftest| async
+// Copyright 2019 Google, Inc. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: prod-OptionalExpression
+description: >
+ optional chain expansions in an async context
+info: |
+ Left-Hand-Side Expressions
+ OptionalExpression
+ MemberExpression [PrimaryExpression Identifier] OptionalChain
+ OptionalChain OptionalChain ?.[Expression]
+features: [optional-chaining]
+flags: [async]
+---*/
+
+async function checkAssertions() {
+ assert.sameValue(await {a: [11]}?.a[0], 11);
+ const b = {c: [22, 33]};
+ assert.sameValue(b?.c[await Promise.resolve(1)], 33);
+ function e(val) {
+ return val;
+ }
+ assert.sameValue({d: e}?.d(await Promise.resolve([44, 55]))[1], 55);
+ assert.sameValue(undefined?.arr[
+ await Promise.reject(new Error('unreachable'))
+ ], undefined);
+}
+checkAssertions().then($DONE, $DONE);
diff --git a/js/src/tests/test262/language/optional-chaining/optional-chain-async-square-brackets.js b/js/src/tests/test262/language/optional-chaining/optional-chain-async-square-brackets.js
new file mode 100644
index 0000000000..38cdab73f2
--- /dev/null
+++ b/js/src/tests/test262/language/optional-chaining/optional-chain-async-square-brackets.js
@@ -0,0 +1,25 @@
+// |reftest| async
+// Copyright 2019 Google, Inc. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: prod-OptionalExpression
+description: >
+ optional chain expansions in an async context
+info: |
+ Left-Hand-Side Expressions
+ OptionalExpression
+ MemberExpression [PrimaryExpression Identifier] OptionalChain
+ OptionalChain ?.[Expression]
+features: [optional-chaining]
+flags: [async]
+---*/
+
+async function checkAssertions() {
+ assert.sameValue(await [11]?.[0], 11);
+ assert.sameValue([22, 33]?.[await Promise.resolve(1)], 33);
+ assert.sameValue([44, await Promise.resolve(55)]?.[1], 55);
+ assert.sameValue(undefined?.[
+ await Promise.reject(new Error('unreachable'))
+ ], undefined);
+}
+checkAssertions().then($DONE, $DONE);
diff --git a/js/src/tests/test262/language/optional-chaining/optional-chain-expression-optional-expression.js b/js/src/tests/test262/language/optional-chaining/optional-chain-expression-optional-expression.js
new file mode 100644
index 0000000000..be898b876e
--- /dev/null
+++ b/js/src/tests/test262/language/optional-chaining/optional-chain-expression-optional-expression.js
@@ -0,0 +1,22 @@
+// Copyright 2019 Google, Inc. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: prod-OptionalExpression
+description: >
+ optional chain bracket notation containing optional expresion
+info: |
+ OptionalChain:
+ ?. [OptionalExpression]
+features: [optional-chaining]
+---*/
+const a = undefined;
+const b = {e: 0};
+const c = {};
+c[undefined] = 11;
+const d = [22];
+
+assert.sameValue(undefined, a?.[a?.b]);
+assert.sameValue(11, c?.[a?.b]);
+assert.sameValue(22, d?.[b?.e]);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/language/optional-chaining/optional-chain-prod-arguments.js b/js/src/tests/test262/language/optional-chaining/optional-chain-prod-arguments.js
new file mode 100644
index 0000000000..c9d9874078
--- /dev/null
+++ b/js/src/tests/test262/language/optional-chaining/optional-chain-prod-arguments.js
@@ -0,0 +1,21 @@
+// Copyright 2020 Salesforce.com, Inc. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: prod-OptionalExpression
+description: >
+ Productions for ?. Arguments
+info: |
+ OptionalChain[Yield, Await]:
+ ?. Arguments
+features: [optional-chaining]
+---*/
+
+function fn(arg1, arg2, arg3 = 0) {
+ return arg1 + arg2 + arg3;
+}
+
+assert.sameValue(fn?.(10, 20), 30, 'regular');
+assert.sameValue(String?.(42), '42', 'built-in');
+assert.sameValue(fn ?. (...[10, 20, 40]), 70, 'spread');
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/language/optional-chaining/optional-chain-prod-expression.js b/js/src/tests/test262/language/optional-chaining/optional-chain-prod-expression.js
new file mode 100644
index 0000000000..dfde4d26c2
--- /dev/null
+++ b/js/src/tests/test262/language/optional-chaining/optional-chain-prod-expression.js
@@ -0,0 +1,44 @@
+// Copyright 2020 Salesforce.com, Inc. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: prod-OptionalExpression
+description: >
+ Productions for ?. [Expression]
+info: |
+ OptionalChain:
+ ?.[ Expression ]
+features: [optional-chaining]
+---*/
+
+const $ = 'x';
+const arr = [39, 42];
+
+arr.true = 'prop';
+arr[1.1] = 'other prop';
+
+const obj = {
+ a: 'hello',
+ undefined: 40,
+ $: 0,
+ NaN: 41,
+ null: 42,
+ x: 43,
+ true: 44
+};
+
+assert.sameValue(arr?.[0], 39, '[0]');
+assert.sameValue(arr?.[0, 1], 42, '[0, 1]');
+assert.sameValue(arr?.[1], 42, '[1]');
+assert.sameValue(arr?.[1, 0], 39, '[1, 0]');
+assert.sameValue(arr?.[{}, NaN, undefined, 2, 0, 10 / 10], 42, '[{}, NaN, undefined, 2, 0, 10 / 10]');
+assert.sameValue(arr?.[true], 'prop', '[true]');
+assert.sameValue(arr?.[1.1], 'other prop', '[1.1]');
+
+assert.sameValue(obj?.[undefined], 40, '[undefined]');
+assert.sameValue(obj?.[NaN], 41, '[NaN]');
+assert.sameValue(obj?.[null], 42, '[null]');
+assert.sameValue(obj?.['$'], 0, '["$"]');
+assert.sameValue(obj?.[$], 43, '[$]');
+assert.sameValue(obj?.[true], 44, '[true]');
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/language/optional-chaining/optional-chain-prod-identifiername.js b/js/src/tests/test262/language/optional-chaining/optional-chain-prod-identifiername.js
new file mode 100644
index 0000000000..2636caf315
--- /dev/null
+++ b/js/src/tests/test262/language/optional-chaining/optional-chain-prod-identifiername.js
@@ -0,0 +1,40 @@
+// Copyright 2020 Salesforce.com, Inc. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: prod-OptionalExpression
+description: >
+ Productions for ?. IdentifierName
+info: |
+ OptionalChain[Yield, Await]:
+ ?. IdentifierName
+features: [optional-chaining]
+---*/
+
+const arr = [10, 11];
+const obj = {
+ a: 'hello'
+};
+
+assert.sameValue(obj?.a, 'hello');
+assert.sameValue(obj?.\u0061, 'hello');
+assert.sameValue(obj?.\u{0061}, 'hello');
+
+assert.sameValue(obj?.\u0062, undefined);
+assert.sameValue(obj?.\u{0062}, undefined);
+
+assert.sameValue(arr ?. length, 2);
+assert.sameValue(arr ?. l\u0065ngth, 2);
+assert.sameValue(arr ?. l\u{0065}ngth, 2);
+
+assert.sameValue(obj?.$, undefined);
+
+obj.$ = 42;
+assert.sameValue(obj?.$, 42);
+
+assert.sameValue(obj?._, undefined);
+
+obj._ = 39;
+assert.sameValue(obj?._, 39);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/language/optional-chaining/optional-chain.js b/js/src/tests/test262/language/optional-chaining/optional-chain.js
new file mode 100644
index 0000000000..b8dd183092
--- /dev/null
+++ b/js/src/tests/test262/language/optional-chaining/optional-chain.js
@@ -0,0 +1,52 @@
+// Copyright 2019 Google, Inc. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: prod-OptionalExpression
+description: >
+ various optional chain expansions
+info: |
+ OptionalChain[Yield, Await]:
+ ?.[Expression]
+ ?.IdentifierName
+ ?.Arguments
+ ?.TemplateLiteral
+ OptionalChain [Expression]
+ OptionalChain .IdentifierName
+ OptionalChain Arguments[?Yield, ?Await]
+ OptionalChain TemplateLiteral
+features: [optional-chaining]
+---*/
+
+const arr = [10, 11];
+const obj = {
+ a: 'hello',
+ b: {val: 13},
+ c(arg1) {
+ return arg1 * 2;
+ },
+ arr: [11, 12]
+};
+const i = 0;
+
+// OptionalChain: ?.[Expression]
+assert.sameValue(11, arr?.[i + 1]);
+
+// OptionalChain: ?.IdentifierName
+assert.sameValue('hello', obj?.a);
+
+// OptionalChain: ?.Arguments
+const fn = (arg1, arg2) => {
+ return arg1 + arg2;
+}
+assert.sameValue(30, fn?.(10, 20));
+
+// OptionalChain: OptionalChain [Expression]
+assert.sameValue(12, obj?.arr[i + 1]);
+
+// OptionalChain: OptionalChain .IdentifierName
+assert.sameValue(13, obj?.b.val);
+
+// OptionalChain: OptionalChain Arguments
+assert.sameValue(20, obj?.c(10));
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/language/optional-chaining/optional-expression.js b/js/src/tests/test262/language/optional-chaining/optional-expression.js
new file mode 100644
index 0000000000..38cba72d21
--- /dev/null
+++ b/js/src/tests/test262/language/optional-chaining/optional-expression.js
@@ -0,0 +1,29 @@
+// Copyright 2019 Google, Inc. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: prod-OptionalExpression
+description: >
+ optional chain on recursive optional expression
+info: |
+ Left-Hand-Side Expressions
+ OptionalExpression:
+ OptionalExpression OptionalChain
+features: [optional-chaining]
+---*/
+
+const obj = {
+ a: {
+ b: 22
+ }
+};
+
+function fn () {
+ return {};
+}
+
+// OptionalExpression (MemberExpression OptionalChain) OptionalChain
+assert.sameValue(22, obj?.a?.b);
+// OptionalExpression (CallExpression OptionalChain) OptionalChain
+assert.sameValue(undefined, fn()?.a?.b);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/language/optional-chaining/punctuator-decimal-lookahead.js b/js/src/tests/test262/language/optional-chaining/punctuator-decimal-lookahead.js
new file mode 100644
index 0000000000..ec64f9201e
--- /dev/null
+++ b/js/src/tests/test262/language/optional-chaining/punctuator-decimal-lookahead.js
@@ -0,0 +1,17 @@
+// Copyright 2019 Google, Inc. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: prod-OptionalExpression
+description: >
+ ternary operation with decimal does not evaluate as optional chain
+info: |
+ Punctuators
+ OptionalChainingPunctuator::
+ ?.[lookahead ∉ DecimalDigit]
+features: [optional-chaining]
+---*/
+
+const value = true ?.30 : false;
+assert.sameValue(.30, value);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/language/optional-chaining/runtime-semantics-evaluation.js b/js/src/tests/test262/language/optional-chaining/runtime-semantics-evaluation.js
new file mode 100644
index 0000000000..a87af57856
--- /dev/null
+++ b/js/src/tests/test262/language/optional-chaining/runtime-semantics-evaluation.js
@@ -0,0 +1,20 @@
+// Copyright 2019 Google, Inc. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: prod-OptionalExpression
+description: >
+ accessing optional value on undefined or null returns undefined.
+info: |
+ If baseValue is undefined or null, then
+ Return undefined.
+features: [optional-chaining]
+---*/
+
+const nul = null;
+const undf = undefined;
+assert.sameValue(undefined, nul?.a);
+assert.sameValue(undefined, undf?.b);
+assert.sameValue(undefined, null?.a);
+assert.sameValue(undefined, undefined?.b);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/language/optional-chaining/shell.js b/js/src/tests/test262/language/optional-chaining/shell.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/language/optional-chaining/shell.js
diff --git a/js/src/tests/test262/language/optional-chaining/short-circuiting.js b/js/src/tests/test262/language/optional-chaining/short-circuiting.js
new file mode 100644
index 0000000000..74295cb1ee
--- /dev/null
+++ b/js/src/tests/test262/language/optional-chaining/short-circuiting.js
@@ -0,0 +1,24 @@
+// Copyright 2019 Google, Inc. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: prod-OptionalExpression
+description: >
+ demonstrate syntax-based short-circuiting.
+info: |
+ If the expression on the LHS of ?. evaluates to null/undefined, the RHS is
+ not evaluated
+features: [optional-chaining]
+---*/
+
+const a = undefined;
+let x = 1;
+
+a?.[++x] // short-circuiting.
+a?.b.c(++x).d; // long short-circuiting.
+
+undefined?.[++x] // short-circuiting.
+undefined?.b.c(++x).d; // long short-circuiting.
+
+assert.sameValue(1, x);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/language/optional-chaining/static-semantics-simple-assignment.js b/js/src/tests/test262/language/optional-chaining/static-semantics-simple-assignment.js
new file mode 100644
index 0000000000..cbbcedba50
--- /dev/null
+++ b/js/src/tests/test262/language/optional-chaining/static-semantics-simple-assignment.js
@@ -0,0 +1,24 @@
+// |reftest| error:SyntaxError
+
+// Copyright 2019 Google, Inc. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: prod-OptionalExpression
+description: >
+ an optional expression cannot be target of assignment
+info: |
+ Static Semantics: IsValidSimpleAssignmentTarget
+ LeftHandSideExpression:
+ OptionalExpression
+ Return false.
+features: [optional-chaining]
+negative:
+ phase: parse
+ type: SyntaxError
+---*/
+
+$DONOTEVALUATE();
+
+const obj = {};
+
+obj?.a = 33;
diff --git a/js/src/tests/test262/language/optional-chaining/super-property-optional-call.js b/js/src/tests/test262/language/optional-chaining/super-property-optional-call.js
new file mode 100644
index 0000000000..21d1635ecc
--- /dev/null
+++ b/js/src/tests/test262/language/optional-chaining/super-property-optional-call.js
@@ -0,0 +1,32 @@
+// Copyright 2019 Google, LLC. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: prod-OptionalExpression
+description: >
+ optional call invoked on super method should be equivalent to call
+info: |
+ OptionalExpression
+ MemberExpression OptionalChain
+ SuperProperty OptionalChain
+features: [optional-chaining]
+---*/
+
+let called = false;
+let context;
+class Base {
+ method() {
+ called = true;
+ context = this;
+ }
+}
+class Foo extends Base {
+ method() {
+ super.method?.();
+ }
+}
+const foo = new Foo();
+foo.method();
+assert(foo === context);
+assert.sameValue(called, true);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/language/optional-chaining/update-expression-postfix.js b/js/src/tests/test262/language/optional-chaining/update-expression-postfix.js
new file mode 100644
index 0000000000..8b8fc68f9a
--- /dev/null
+++ b/js/src/tests/test262/language/optional-chaining/update-expression-postfix.js
@@ -0,0 +1,24 @@
+// |reftest| error:SyntaxError
+// Copyright 2019 Google, Inc. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: prod-OptionalExpression
+description: >
+ optional chaining is forbidden in write contexts
+info: |
+ UpdateExpression[Yield, Await]:
+ LeftHandSideExpression++
+ LeftHandSideExpression--
+ ++UnaryExpression
+ --UnaryExpression
+features: [optional-chaining]
+negative:
+ phase: parse
+ type: SyntaxError
+---*/
+
+$DONOTEVALUATE();
+
+// LeftHandSideExpression ++
+const a = {};
+a?.b++;
diff --git a/js/src/tests/test262/language/optional-chaining/update-expression-prefix.js b/js/src/tests/test262/language/optional-chaining/update-expression-prefix.js
new file mode 100644
index 0000000000..ba65aadc0c
--- /dev/null
+++ b/js/src/tests/test262/language/optional-chaining/update-expression-prefix.js
@@ -0,0 +1,24 @@
+// |reftest| error:SyntaxError
+// Copyright 2019 Google, Inc. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: prod-OptionalExpression
+description: >
+ optional chaining is forbidden in write contexts
+info: |
+ UpdateExpression[Yield, Await]:
+ LeftHandSideExpression++
+ LeftHandSideExpression--
+ ++UnaryExpression
+ --UnaryExpression
+features: [optional-chaining]
+negative:
+ phase: parse
+ type: SyntaxError
+---*/
+
+$DONOTEVALUATE();
+
+// --UnaryExpression
+const a = {};
+--a?.b;
diff --git a/js/src/tests/test262/language/statements/for-in/dstr/array-elem-nested-memberexpr-optchain-prop-ref-init.js b/js/src/tests/test262/language/statements/for-in/dstr/array-elem-nested-memberexpr-optchain-prop-ref-init.js
new file mode 100644
index 0000000000..f07643b8f2
--- /dev/null
+++ b/js/src/tests/test262/language/statements/for-in/dstr/array-elem-nested-memberexpr-optchain-prop-ref-init.js
@@ -0,0 +1,66 @@
+// |reftest| error:SyntaxError
+// This file was procedurally generated from the following sources:
+// - src/dstr-assignment/array-elem-nested-memberexpr-optchain-prop-ref-init.case
+// - src/dstr-assignment/syntax/for-in.template
+/*---
+description: It is a Syntax Error if LeftHandSideExpression of an DestructuringAssignmentTarget is neither an ObjectLiteral nor an ArrayLiteral and AssignmentTargetType(LeftHandSideExpression) is not simple Using Object (MemberExpression OptionalChain .IdentifierName Initializer) (For..in statement)
+esid: sec-for-in-and-for-of-statements-runtime-semantics-labelledevaluation
+features: [optional-chaining, destructuring-binding]
+flags: [generated]
+negative:
+ phase: parse
+ type: SyntaxError
+info: |
+ IterationStatement :
+ for ( LeftHandSideExpression of AssignmentExpression ) Statement
+
+ 1. Let keyResult be the result of performing ? ForIn/OfHeadEvaluation(« »,
+ AssignmentExpression, iterate).
+ 2. Return ? ForIn/OfBodyEvaluation(LeftHandSideExpression, Statement,
+ keyResult, assignment, labelSet).
+
+ 13.7.5.13 Runtime Semantics: ForIn/OfBodyEvaluation
+
+ [...]
+ 4. If destructuring is true and if lhsKind is assignment, then
+ a. Assert: lhs is a LeftHandSideExpression.
+ b. Let assignmentPattern be the parse of the source text corresponding to
+ lhs using AssignmentPattern as the goal symbol.
+ [...]
+
+ Syntax
+
+ AssignmentElement : DestructuringAssignmentTarget Initializer_opt
+ DestructuringAssignmentTarget : LeftHandSideExpression
+
+ Static Semantics: Early Errors
+
+ OptionalExpression:
+ MemberExpression OptionalChain
+ CallExpression OptionalChain
+ OptionalExpression OptionalChain
+
+ OptionalChain:
+ ?. [ Expression ]
+ ?. IdentifierName
+ ?. Arguments
+ ?. TemplateLiteral
+ OptionalChain [ Expression ]
+ OptionalChain .IdentifierName
+ OptionalChain Arguments
+ OptionalChain TemplateLiteral
+
+ DestructuringAssignmentTarget : LeftHandSideExpression
+
+ - It is a Syntax Error if LeftHandSideExpression is neither an ObjectLiteral nor an ArrayLiteral and IsValidSimpleAssignmentTarget(LeftHandSideExpression) is not true.
+
+ Static Semantics: IsValidSimpleAssignmentTarget
+
+ LeftHandSideExpression : OptionalExpression
+ 1. Return false.
+
+---*/
+$DONOTEVALUATE();
+var x = {};
+
+for ([x?.y = 42] in [[23]]) ;
diff --git a/js/src/tests/test262/language/statements/for-in/dstr/array-elem-nested-memberexpr-optchain-prop-ref.js b/js/src/tests/test262/language/statements/for-in/dstr/array-elem-nested-memberexpr-optchain-prop-ref.js
new file mode 100644
index 0000000000..179c4f1992
--- /dev/null
+++ b/js/src/tests/test262/language/statements/for-in/dstr/array-elem-nested-memberexpr-optchain-prop-ref.js
@@ -0,0 +1,66 @@
+// |reftest| error:SyntaxError
+// This file was procedurally generated from the following sources:
+// - src/dstr-assignment/array-elem-nested-memberexpr-optchain-prop-ref.case
+// - src/dstr-assignment/syntax/for-in.template
+/*---
+description: It is a Syntax Error if LeftHandSideExpression of an DestructuringAssignmentTarget is neither an ObjectLiteral nor an ArrayLiteral and AssignmentTargetType(LeftHandSideExpression) is not simple Using Object (MemberExpression OptionalChain .IdentifierName) (For..in statement)
+esid: sec-for-in-and-for-of-statements-runtime-semantics-labelledevaluation
+features: [optional-chaining, destructuring-binding]
+flags: [generated]
+negative:
+ phase: parse
+ type: SyntaxError
+info: |
+ IterationStatement :
+ for ( LeftHandSideExpression of AssignmentExpression ) Statement
+
+ 1. Let keyResult be the result of performing ? ForIn/OfHeadEvaluation(« »,
+ AssignmentExpression, iterate).
+ 2. Return ? ForIn/OfBodyEvaluation(LeftHandSideExpression, Statement,
+ keyResult, assignment, labelSet).
+
+ 13.7.5.13 Runtime Semantics: ForIn/OfBodyEvaluation
+
+ [...]
+ 4. If destructuring is true and if lhsKind is assignment, then
+ a. Assert: lhs is a LeftHandSideExpression.
+ b. Let assignmentPattern be the parse of the source text corresponding to
+ lhs using AssignmentPattern as the goal symbol.
+ [...]
+
+ Syntax
+
+ AssignmentElement : DestructuringAssignmentTarget Initializer_opt
+ DestructuringAssignmentTarget : LeftHandSideExpression
+
+ Static Semantics: Early Errors
+
+ OptionalExpression:
+ MemberExpression OptionalChain
+ CallExpression OptionalChain
+ OptionalExpression OptionalChain
+
+ OptionalChain:
+ ?. [ Expression ]
+ ?. IdentifierName
+ ?. Arguments
+ ?. TemplateLiteral
+ OptionalChain [ Expression ]
+ OptionalChain .IdentifierName
+ OptionalChain Arguments
+ OptionalChain TemplateLiteral
+
+ DestructuringAssignmentTarget : LeftHandSideExpression
+
+ - It is a Syntax Error if LeftHandSideExpression is neither an ObjectLiteral nor an ArrayLiteral and IsValidSimpleAssignmentTarget(LeftHandSideExpression) is not true.
+
+ Static Semantics: IsValidSimpleAssignmentTarget
+
+ LeftHandSideExpression : OptionalExpression
+ 1. Return false.
+
+---*/
+$DONOTEVALUATE();
+var x = {};
+
+for ([x?.y] in [[23]]) ;
diff --git a/js/src/tests/test262/language/statements/for-in/dstr/array-elem-put-obj-literal-optchain-prop-ref-init.js b/js/src/tests/test262/language/statements/for-in/dstr/array-elem-put-obj-literal-optchain-prop-ref-init.js
new file mode 100644
index 0000000000..1b05d6fd99
--- /dev/null
+++ b/js/src/tests/test262/language/statements/for-in/dstr/array-elem-put-obj-literal-optchain-prop-ref-init.js
@@ -0,0 +1,69 @@
+// |reftest| error:SyntaxError
+// This file was procedurally generated from the following sources:
+// - src/dstr-assignment/array-elem-put-obj-literal-optchain-prop-ref-init.case
+// - src/dstr-assignment/syntax/for-in.template
+/*---
+description: It is a Syntax Error if LeftHandSideExpression of an DestructuringAssignmentTarget is neither an ObjectLiteral nor an ArrayLiteral and AssignmentTargetType(LeftHandSideExpression) is not simple Using Object (For..in statement)
+esid: sec-for-in-and-for-of-statements-runtime-semantics-labelledevaluation
+features: [optional-chaining, destructuring-binding]
+flags: [generated]
+negative:
+ phase: parse
+ type: SyntaxError
+info: |
+ IterationStatement :
+ for ( LeftHandSideExpression of AssignmentExpression ) Statement
+
+ 1. Let keyResult be the result of performing ? ForIn/OfHeadEvaluation(« »,
+ AssignmentExpression, iterate).
+ 2. Return ? ForIn/OfBodyEvaluation(LeftHandSideExpression, Statement,
+ keyResult, assignment, labelSet).
+
+ 13.7.5.13 Runtime Semantics: ForIn/OfBodyEvaluation
+
+ [...]
+ 4. If destructuring is true and if lhsKind is assignment, then
+ a. Assert: lhs is a LeftHandSideExpression.
+ b. Let assignmentPattern be the parse of the source text corresponding to
+ lhs using AssignmentPattern as the goal symbol.
+ [...]
+
+ Syntax
+
+ AssignmentElement : DestructuringAssignmentTarget Initializer_opt
+ DestructuringAssignmentTarget : LeftHandSideExpression
+
+ Static Semantics: Early Errors
+
+ OptionalExpression:
+ MemberExpression OptionalChain
+ CallExpression OptionalChain
+ OptionalExpression OptionalChain
+
+ OptionalChain:
+ ?. [ Expression ]
+ ?. IdentifierName
+ ?. Arguments
+ ?. TemplateLiteral
+ OptionalChain [ Expression ]
+ OptionalChain .IdentifierName
+ OptionalChain Arguments
+ OptionalChain TemplateLiteral
+
+ DestructuringAssignmentTarget : LeftHandSideExpression
+
+ - It is a Syntax Error if LeftHandSideExpression is neither an ObjectLiteral nor an ArrayLiteral and IsValidSimpleAssignmentTarget(LeftHandSideExpression) is not true.
+
+ Static Semantics: IsValidSimpleAssignmentTarget
+
+ LeftHandSideExpression : OptionalExpression
+ 1. Return false.
+
+---*/
+$DONOTEVALUATE();
+
+for ([{
+ set y(val) {
+ throw new Test262Error('The property should not be accessed.');
+ }
+}?.y = 42] in [[23]]) ;
diff --git a/js/src/tests/test262/language/statements/for-in/dstr/array-elem-put-obj-literal-optchain-prop-ref.js b/js/src/tests/test262/language/statements/for-in/dstr/array-elem-put-obj-literal-optchain-prop-ref.js
new file mode 100644
index 0000000000..1f7780136d
--- /dev/null
+++ b/js/src/tests/test262/language/statements/for-in/dstr/array-elem-put-obj-literal-optchain-prop-ref.js
@@ -0,0 +1,69 @@
+// |reftest| error:SyntaxError
+// This file was procedurally generated from the following sources:
+// - src/dstr-assignment/array-elem-put-obj-literal-optchain-prop-ref.case
+// - src/dstr-assignment/syntax/for-in.template
+/*---
+description: It is a Syntax Error if LeftHandSideExpression of an DestructuringAssignmentTarget is neither an ObjectLiteral nor an ArrayLiteral and AssignmentTargetType(LeftHandSideExpression) is not simple Using Object (For..in statement)
+esid: sec-for-in-and-for-of-statements-runtime-semantics-labelledevaluation
+features: [optional-chaining, destructuring-binding]
+flags: [generated]
+negative:
+ phase: parse
+ type: SyntaxError
+info: |
+ IterationStatement :
+ for ( LeftHandSideExpression of AssignmentExpression ) Statement
+
+ 1. Let keyResult be the result of performing ? ForIn/OfHeadEvaluation(« »,
+ AssignmentExpression, iterate).
+ 2. Return ? ForIn/OfBodyEvaluation(LeftHandSideExpression, Statement,
+ keyResult, assignment, labelSet).
+
+ 13.7.5.13 Runtime Semantics: ForIn/OfBodyEvaluation
+
+ [...]
+ 4. If destructuring is true and if lhsKind is assignment, then
+ a. Assert: lhs is a LeftHandSideExpression.
+ b. Let assignmentPattern be the parse of the source text corresponding to
+ lhs using AssignmentPattern as the goal symbol.
+ [...]
+
+ Syntax
+
+ AssignmentElement : DestructuringAssignmentTarget Initializer_opt
+ DestructuringAssignmentTarget : LeftHandSideExpression
+
+ Static Semantics: Early Errors
+
+ OptionalExpression:
+ MemberExpression OptionalChain
+ CallExpression OptionalChain
+ OptionalExpression OptionalChain
+
+ OptionalChain:
+ ?. [ Expression ]
+ ?. IdentifierName
+ ?. Arguments
+ ?. TemplateLiteral
+ OptionalChain [ Expression ]
+ OptionalChain .IdentifierName
+ OptionalChain Arguments
+ OptionalChain TemplateLiteral
+
+ DestructuringAssignmentTarget : LeftHandSideExpression
+
+ - It is a Syntax Error if LeftHandSideExpression is neither an ObjectLiteral nor an ArrayLiteral and IsValidSimpleAssignmentTarget(LeftHandSideExpression) is not true.
+
+ Static Semantics: IsValidSimpleAssignmentTarget
+
+ LeftHandSideExpression : OptionalExpression
+ 1. Return false.
+
+---*/
+$DONOTEVALUATE();
+
+for ([{
+ set y(val) {
+ throw new Test262Error('The property should not be accessed.');
+ }
+}?.y] in [[23]]) ;
diff --git a/js/src/tests/test262/language/statements/for-in/dstr/obj-prop-elem-target-memberexpr-optchain-prop-ref-init.js b/js/src/tests/test262/language/statements/for-in/dstr/obj-prop-elem-target-memberexpr-optchain-prop-ref-init.js
new file mode 100644
index 0000000000..91c8913af4
--- /dev/null
+++ b/js/src/tests/test262/language/statements/for-in/dstr/obj-prop-elem-target-memberexpr-optchain-prop-ref-init.js
@@ -0,0 +1,66 @@
+// |reftest| error:SyntaxError
+// This file was procedurally generated from the following sources:
+// - src/dstr-assignment/obj-prop-elem-target-memberexpr-optchain-prop-ref-init.case
+// - src/dstr-assignment/syntax/for-in.template
+/*---
+description: It is a Syntax Error if LeftHandSideExpression of an DestructuringAssignmentTarget is neither an ObjectLiteral nor an ArrayLiteral and AssignmentTargetType(LeftHandSideExpression) is not simple Using Object (MemberExpression OptionalChain .IdentifierName Initializer) (For..in statement)
+esid: sec-for-in-and-for-of-statements-runtime-semantics-labelledevaluation
+features: [optional-chaining, destructuring-binding]
+flags: [generated]
+negative:
+ phase: parse
+ type: SyntaxError
+info: |
+ IterationStatement :
+ for ( LeftHandSideExpression of AssignmentExpression ) Statement
+
+ 1. Let keyResult be the result of performing ? ForIn/OfHeadEvaluation(« »,
+ AssignmentExpression, iterate).
+ 2. Return ? ForIn/OfBodyEvaluation(LeftHandSideExpression, Statement,
+ keyResult, assignment, labelSet).
+
+ 13.7.5.13 Runtime Semantics: ForIn/OfBodyEvaluation
+
+ [...]
+ 4. If destructuring is true and if lhsKind is assignment, then
+ a. Assert: lhs is a LeftHandSideExpression.
+ b. Let assignmentPattern be the parse of the source text corresponding to
+ lhs using AssignmentPattern as the goal symbol.
+ [...]
+
+ Syntax
+
+ AssignmentElement : DestructuringAssignmentTarget Initializer_opt
+ DestructuringAssignmentTarget : LeftHandSideExpression
+
+ Static Semantics: Early Errors
+
+ OptionalExpression:
+ MemberExpression OptionalChain
+ CallExpression OptionalChain
+ OptionalExpression OptionalChain
+
+ OptionalChain:
+ ?. [ Expression ]
+ ?. IdentifierName
+ ?. Arguments
+ ?. TemplateLiteral
+ OptionalChain [ Expression ]
+ OptionalChain .IdentifierName
+ OptionalChain Arguments
+ OptionalChain TemplateLiteral
+
+ DestructuringAssignmentTarget : LeftHandSideExpression
+
+ - It is a Syntax Error if LeftHandSideExpression is neither an ObjectLiteral nor an ArrayLiteral and IsValidSimpleAssignmentTarget(LeftHandSideExpression) is not true.
+
+ Static Semantics: IsValidSimpleAssignmentTarget
+
+ LeftHandSideExpression : OptionalExpression
+ 1. Return false.
+
+---*/
+$DONOTEVALUATE();
+var y = {};
+
+for ({ x: y?.z = 42 } in [{ x: 23 }]) ;
diff --git a/js/src/tests/test262/language/statements/for-in/dstr/obj-prop-elem-target-memberexpr-optchain-prop-ref.js b/js/src/tests/test262/language/statements/for-in/dstr/obj-prop-elem-target-memberexpr-optchain-prop-ref.js
new file mode 100644
index 0000000000..be0b5b7f34
--- /dev/null
+++ b/js/src/tests/test262/language/statements/for-in/dstr/obj-prop-elem-target-memberexpr-optchain-prop-ref.js
@@ -0,0 +1,66 @@
+// |reftest| error:SyntaxError
+// This file was procedurally generated from the following sources:
+// - src/dstr-assignment/obj-prop-elem-target-memberexpr-optchain-prop-ref.case
+// - src/dstr-assignment/syntax/for-in.template
+/*---
+description: It is a Syntax Error if LeftHandSideExpression of an DestructuringAssignmentTarget is neither an ObjectLiteral nor an ArrayLiteral and AssignmentTargetType(LeftHandSideExpression) is not simple Using Object (MemberExpression OptionalChain .IdentifierName) (For..in statement)
+esid: sec-for-in-and-for-of-statements-runtime-semantics-labelledevaluation
+features: [optional-chaining, destructuring-binding]
+flags: [generated]
+negative:
+ phase: parse
+ type: SyntaxError
+info: |
+ IterationStatement :
+ for ( LeftHandSideExpression of AssignmentExpression ) Statement
+
+ 1. Let keyResult be the result of performing ? ForIn/OfHeadEvaluation(« »,
+ AssignmentExpression, iterate).
+ 2. Return ? ForIn/OfBodyEvaluation(LeftHandSideExpression, Statement,
+ keyResult, assignment, labelSet).
+
+ 13.7.5.13 Runtime Semantics: ForIn/OfBodyEvaluation
+
+ [...]
+ 4. If destructuring is true and if lhsKind is assignment, then
+ a. Assert: lhs is a LeftHandSideExpression.
+ b. Let assignmentPattern be the parse of the source text corresponding to
+ lhs using AssignmentPattern as the goal symbol.
+ [...]
+
+ Syntax
+
+ AssignmentElement : DestructuringAssignmentTarget Initializer_opt
+ DestructuringAssignmentTarget : LeftHandSideExpression
+
+ Static Semantics: Early Errors
+
+ OptionalExpression:
+ MemberExpression OptionalChain
+ CallExpression OptionalChain
+ OptionalExpression OptionalChain
+
+ OptionalChain:
+ ?. [ Expression ]
+ ?. IdentifierName
+ ?. Arguments
+ ?. TemplateLiteral
+ OptionalChain [ Expression ]
+ OptionalChain .IdentifierName
+ OptionalChain Arguments
+ OptionalChain TemplateLiteral
+
+ DestructuringAssignmentTarget : LeftHandSideExpression
+
+ - It is a Syntax Error if LeftHandSideExpression is neither an ObjectLiteral nor an ArrayLiteral and IsValidSimpleAssignmentTarget(LeftHandSideExpression) is not true.
+
+ Static Semantics: IsValidSimpleAssignmentTarget
+
+ LeftHandSideExpression : OptionalExpression
+ 1. Return false.
+
+---*/
+$DONOTEVALUATE();
+var y = {};
+
+for ({ x: y?.z } in [{ x: 23 }]) ;
diff --git a/js/src/tests/test262/language/statements/for-in/dstr/obj-prop-elem-target-obj-literal-optchain-prop-ref-init.js b/js/src/tests/test262/language/statements/for-in/dstr/obj-prop-elem-target-obj-literal-optchain-prop-ref-init.js
new file mode 100644
index 0000000000..ba16f696e3
--- /dev/null
+++ b/js/src/tests/test262/language/statements/for-in/dstr/obj-prop-elem-target-obj-literal-optchain-prop-ref-init.js
@@ -0,0 +1,69 @@
+// |reftest| error:SyntaxError
+// This file was procedurally generated from the following sources:
+// - src/dstr-assignment/obj-prop-elem-target-obj-literal-optchain-prop-ref-init.case
+// - src/dstr-assignment/syntax/for-in.template
+/*---
+description: It is a Syntax Error if LeftHandSideExpression of an DestructuringAssignmentTarget is neither an ObjectLiteral nor an ArrayLiteral and AssignmentTargetType(LeftHandSideExpression) is not simple Using Object (For..in statement)
+esid: sec-for-in-and-for-of-statements-runtime-semantics-labelledevaluation
+features: [optional-chaining, destructuring-binding]
+flags: [generated]
+negative:
+ phase: parse
+ type: SyntaxError
+info: |
+ IterationStatement :
+ for ( LeftHandSideExpression of AssignmentExpression ) Statement
+
+ 1. Let keyResult be the result of performing ? ForIn/OfHeadEvaluation(« »,
+ AssignmentExpression, iterate).
+ 2. Return ? ForIn/OfBodyEvaluation(LeftHandSideExpression, Statement,
+ keyResult, assignment, labelSet).
+
+ 13.7.5.13 Runtime Semantics: ForIn/OfBodyEvaluation
+
+ [...]
+ 4. If destructuring is true and if lhsKind is assignment, then
+ a. Assert: lhs is a LeftHandSideExpression.
+ b. Let assignmentPattern be the parse of the source text corresponding to
+ lhs using AssignmentPattern as the goal symbol.
+ [...]
+
+ Syntax
+
+ AssignmentElement : DestructuringAssignmentTarget Initializer_opt
+ DestructuringAssignmentTarget : LeftHandSideExpression
+
+ Static Semantics: Early Errors
+
+ OptionalExpression:
+ MemberExpression OptionalChain
+ CallExpression OptionalChain
+ OptionalExpression OptionalChain
+
+ OptionalChain:
+ ?. [ Expression ]
+ ?. IdentifierName
+ ?. Arguments
+ ?. TemplateLiteral
+ OptionalChain [ Expression ]
+ OptionalChain .IdentifierName
+ OptionalChain Arguments
+ OptionalChain TemplateLiteral
+
+ DestructuringAssignmentTarget : LeftHandSideExpression
+
+ - It is a Syntax Error if LeftHandSideExpression is neither an ObjectLiteral nor an ArrayLiteral and IsValidSimpleAssignmentTarget(LeftHandSideExpression) is not true.
+
+ Static Semantics: IsValidSimpleAssignmentTarget
+
+ LeftHandSideExpression : OptionalExpression
+ 1. Return false.
+
+---*/
+$DONOTEVALUATE();
+
+for ({ x: {
+ set y(val) {
+ throw new Test262Error('The property should not be accessed.');
+ }
+}?.y = 42} in [{x: 42}]) ;
diff --git a/js/src/tests/test262/language/statements/for-in/dstr/obj-prop-elem-target-obj-literal-optchain-prop-ref.js b/js/src/tests/test262/language/statements/for-in/dstr/obj-prop-elem-target-obj-literal-optchain-prop-ref.js
new file mode 100644
index 0000000000..c4e02dacbd
--- /dev/null
+++ b/js/src/tests/test262/language/statements/for-in/dstr/obj-prop-elem-target-obj-literal-optchain-prop-ref.js
@@ -0,0 +1,69 @@
+// |reftest| error:SyntaxError
+// This file was procedurally generated from the following sources:
+// - src/dstr-assignment/obj-prop-elem-target-obj-literal-optchain-prop-ref.case
+// - src/dstr-assignment/syntax/for-in.template
+/*---
+description: It is a Syntax Error if LeftHandSideExpression of an DestructuringAssignmentTarget is neither an ObjectLiteral nor an ArrayLiteral and AssignmentTargetType(LeftHandSideExpression) is not simple Using Object (For..in statement)
+esid: sec-for-in-and-for-of-statements-runtime-semantics-labelledevaluation
+features: [optional-chaining, destructuring-binding]
+flags: [generated]
+negative:
+ phase: parse
+ type: SyntaxError
+info: |
+ IterationStatement :
+ for ( LeftHandSideExpression of AssignmentExpression ) Statement
+
+ 1. Let keyResult be the result of performing ? ForIn/OfHeadEvaluation(« »,
+ AssignmentExpression, iterate).
+ 2. Return ? ForIn/OfBodyEvaluation(LeftHandSideExpression, Statement,
+ keyResult, assignment, labelSet).
+
+ 13.7.5.13 Runtime Semantics: ForIn/OfBodyEvaluation
+
+ [...]
+ 4. If destructuring is true and if lhsKind is assignment, then
+ a. Assert: lhs is a LeftHandSideExpression.
+ b. Let assignmentPattern be the parse of the source text corresponding to
+ lhs using AssignmentPattern as the goal symbol.
+ [...]
+
+ Syntax
+
+ AssignmentElement : DestructuringAssignmentTarget Initializer_opt
+ DestructuringAssignmentTarget : LeftHandSideExpression
+
+ Static Semantics: Early Errors
+
+ OptionalExpression:
+ MemberExpression OptionalChain
+ CallExpression OptionalChain
+ OptionalExpression OptionalChain
+
+ OptionalChain:
+ ?. [ Expression ]
+ ?. IdentifierName
+ ?. Arguments
+ ?. TemplateLiteral
+ OptionalChain [ Expression ]
+ OptionalChain .IdentifierName
+ OptionalChain Arguments
+ OptionalChain TemplateLiteral
+
+ DestructuringAssignmentTarget : LeftHandSideExpression
+
+ - It is a Syntax Error if LeftHandSideExpression is neither an ObjectLiteral nor an ArrayLiteral and IsValidSimpleAssignmentTarget(LeftHandSideExpression) is not true.
+
+ Static Semantics: IsValidSimpleAssignmentTarget
+
+ LeftHandSideExpression : OptionalExpression
+ 1. Return false.
+
+---*/
+$DONOTEVALUATE();
+
+for ({ x: {
+ set y(val) {
+ throw new Test262Error('The property should not be accessed.');
+ }
+}?.y} in [{x: 42}]) ;
diff --git a/js/src/tests/test262/language/statements/for-in/dstr/shell.js b/js/src/tests/test262/language/statements/for-in/dstr/shell.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/language/statements/for-in/dstr/shell.js
diff --git a/js/src/tests/test262/language/statements/for-in/shell.js b/js/src/tests/test262/language/statements/for-in/shell.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/language/statements/for-in/shell.js
diff --git a/js/src/tests/test262/language/statements/for-of/dstr/array-elem-nested-memberexpr-optchain-prop-ref-init.js b/js/src/tests/test262/language/statements/for-of/dstr/array-elem-nested-memberexpr-optchain-prop-ref-init.js
new file mode 100644
index 0000000000..7c69c77bbe
--- /dev/null
+++ b/js/src/tests/test262/language/statements/for-of/dstr/array-elem-nested-memberexpr-optchain-prop-ref-init.js
@@ -0,0 +1,66 @@
+// |reftest| error:SyntaxError
+// This file was procedurally generated from the following sources:
+// - src/dstr-assignment/array-elem-nested-memberexpr-optchain-prop-ref-init.case
+// - src/dstr-assignment/syntax/for-of.template
+/*---
+description: It is a Syntax Error if LeftHandSideExpression of an DestructuringAssignmentTarget is neither an ObjectLiteral nor an ArrayLiteral and AssignmentTargetType(LeftHandSideExpression) is not simple Using Object (MemberExpression OptionalChain .IdentifierName Initializer) (For..of statement)
+esid: sec-for-in-and-for-of-statements-runtime-semantics-labelledevaluation
+features: [optional-chaining, destructuring-binding]
+flags: [generated]
+negative:
+ phase: parse
+ type: SyntaxError
+info: |
+ IterationStatement :
+ for ( LeftHandSideExpression of AssignmentExpression ) Statement
+
+ 1. Let keyResult be the result of performing ? ForIn/OfHeadEvaluation(« »,
+ AssignmentExpression, iterate).
+ 2. Return ? ForIn/OfBodyEvaluation(LeftHandSideExpression, Statement,
+ keyResult, assignment, labelSet).
+
+ 13.7.5.13 Runtime Semantics: ForIn/OfBodyEvaluation
+
+ [...]
+ 4. If destructuring is true and if lhsKind is assignment, then
+ a. Assert: lhs is a LeftHandSideExpression.
+ b. Let assignmentPattern be the parse of the source text corresponding to
+ lhs using AssignmentPattern as the goal symbol.
+ [...]
+
+ Syntax
+
+ AssignmentElement : DestructuringAssignmentTarget Initializer_opt
+ DestructuringAssignmentTarget : LeftHandSideExpression
+
+ Static Semantics: Early Errors
+
+ OptionalExpression:
+ MemberExpression OptionalChain
+ CallExpression OptionalChain
+ OptionalExpression OptionalChain
+
+ OptionalChain:
+ ?. [ Expression ]
+ ?. IdentifierName
+ ?. Arguments
+ ?. TemplateLiteral
+ OptionalChain [ Expression ]
+ OptionalChain .IdentifierName
+ OptionalChain Arguments
+ OptionalChain TemplateLiteral
+
+ DestructuringAssignmentTarget : LeftHandSideExpression
+
+ - It is a Syntax Error if LeftHandSideExpression is neither an ObjectLiteral nor an ArrayLiteral and IsValidSimpleAssignmentTarget(LeftHandSideExpression) is not true.
+
+ Static Semantics: IsValidSimpleAssignmentTarget
+
+ LeftHandSideExpression : OptionalExpression
+ 1. Return false.
+
+---*/
+$DONOTEVALUATE();
+var x = {};
+
+for ([x?.y = 42] of [[23]]) ;
diff --git a/js/src/tests/test262/language/statements/for-of/dstr/array-elem-nested-memberexpr-optchain-prop-ref.js b/js/src/tests/test262/language/statements/for-of/dstr/array-elem-nested-memberexpr-optchain-prop-ref.js
new file mode 100644
index 0000000000..6b9072f884
--- /dev/null
+++ b/js/src/tests/test262/language/statements/for-of/dstr/array-elem-nested-memberexpr-optchain-prop-ref.js
@@ -0,0 +1,66 @@
+// |reftest| error:SyntaxError
+// This file was procedurally generated from the following sources:
+// - src/dstr-assignment/array-elem-nested-memberexpr-optchain-prop-ref.case
+// - src/dstr-assignment/syntax/for-of.template
+/*---
+description: It is a Syntax Error if LeftHandSideExpression of an DestructuringAssignmentTarget is neither an ObjectLiteral nor an ArrayLiteral and AssignmentTargetType(LeftHandSideExpression) is not simple Using Object (MemberExpression OptionalChain .IdentifierName) (For..of statement)
+esid: sec-for-in-and-for-of-statements-runtime-semantics-labelledevaluation
+features: [optional-chaining, destructuring-binding]
+flags: [generated]
+negative:
+ phase: parse
+ type: SyntaxError
+info: |
+ IterationStatement :
+ for ( LeftHandSideExpression of AssignmentExpression ) Statement
+
+ 1. Let keyResult be the result of performing ? ForIn/OfHeadEvaluation(« »,
+ AssignmentExpression, iterate).
+ 2. Return ? ForIn/OfBodyEvaluation(LeftHandSideExpression, Statement,
+ keyResult, assignment, labelSet).
+
+ 13.7.5.13 Runtime Semantics: ForIn/OfBodyEvaluation
+
+ [...]
+ 4. If destructuring is true and if lhsKind is assignment, then
+ a. Assert: lhs is a LeftHandSideExpression.
+ b. Let assignmentPattern be the parse of the source text corresponding to
+ lhs using AssignmentPattern as the goal symbol.
+ [...]
+
+ Syntax
+
+ AssignmentElement : DestructuringAssignmentTarget Initializer_opt
+ DestructuringAssignmentTarget : LeftHandSideExpression
+
+ Static Semantics: Early Errors
+
+ OptionalExpression:
+ MemberExpression OptionalChain
+ CallExpression OptionalChain
+ OptionalExpression OptionalChain
+
+ OptionalChain:
+ ?. [ Expression ]
+ ?. IdentifierName
+ ?. Arguments
+ ?. TemplateLiteral
+ OptionalChain [ Expression ]
+ OptionalChain .IdentifierName
+ OptionalChain Arguments
+ OptionalChain TemplateLiteral
+
+ DestructuringAssignmentTarget : LeftHandSideExpression
+
+ - It is a Syntax Error if LeftHandSideExpression is neither an ObjectLiteral nor an ArrayLiteral and IsValidSimpleAssignmentTarget(LeftHandSideExpression) is not true.
+
+ Static Semantics: IsValidSimpleAssignmentTarget
+
+ LeftHandSideExpression : OptionalExpression
+ 1. Return false.
+
+---*/
+$DONOTEVALUATE();
+var x = {};
+
+for ([x?.y] of [[23]]) ;
diff --git a/js/src/tests/test262/language/statements/for-of/dstr/array-elem-put-obj-literal-optchain-prop-ref-init.js b/js/src/tests/test262/language/statements/for-of/dstr/array-elem-put-obj-literal-optchain-prop-ref-init.js
new file mode 100644
index 0000000000..b83831dde1
--- /dev/null
+++ b/js/src/tests/test262/language/statements/for-of/dstr/array-elem-put-obj-literal-optchain-prop-ref-init.js
@@ -0,0 +1,69 @@
+// |reftest| error:SyntaxError
+// This file was procedurally generated from the following sources:
+// - src/dstr-assignment/array-elem-put-obj-literal-optchain-prop-ref-init.case
+// - src/dstr-assignment/syntax/for-of.template
+/*---
+description: It is a Syntax Error if LeftHandSideExpression of an DestructuringAssignmentTarget is neither an ObjectLiteral nor an ArrayLiteral and AssignmentTargetType(LeftHandSideExpression) is not simple Using Object (For..of statement)
+esid: sec-for-in-and-for-of-statements-runtime-semantics-labelledevaluation
+features: [optional-chaining, destructuring-binding]
+flags: [generated]
+negative:
+ phase: parse
+ type: SyntaxError
+info: |
+ IterationStatement :
+ for ( LeftHandSideExpression of AssignmentExpression ) Statement
+
+ 1. Let keyResult be the result of performing ? ForIn/OfHeadEvaluation(« »,
+ AssignmentExpression, iterate).
+ 2. Return ? ForIn/OfBodyEvaluation(LeftHandSideExpression, Statement,
+ keyResult, assignment, labelSet).
+
+ 13.7.5.13 Runtime Semantics: ForIn/OfBodyEvaluation
+
+ [...]
+ 4. If destructuring is true and if lhsKind is assignment, then
+ a. Assert: lhs is a LeftHandSideExpression.
+ b. Let assignmentPattern be the parse of the source text corresponding to
+ lhs using AssignmentPattern as the goal symbol.
+ [...]
+
+ Syntax
+
+ AssignmentElement : DestructuringAssignmentTarget Initializer_opt
+ DestructuringAssignmentTarget : LeftHandSideExpression
+
+ Static Semantics: Early Errors
+
+ OptionalExpression:
+ MemberExpression OptionalChain
+ CallExpression OptionalChain
+ OptionalExpression OptionalChain
+
+ OptionalChain:
+ ?. [ Expression ]
+ ?. IdentifierName
+ ?. Arguments
+ ?. TemplateLiteral
+ OptionalChain [ Expression ]
+ OptionalChain .IdentifierName
+ OptionalChain Arguments
+ OptionalChain TemplateLiteral
+
+ DestructuringAssignmentTarget : LeftHandSideExpression
+
+ - It is a Syntax Error if LeftHandSideExpression is neither an ObjectLiteral nor an ArrayLiteral and IsValidSimpleAssignmentTarget(LeftHandSideExpression) is not true.
+
+ Static Semantics: IsValidSimpleAssignmentTarget
+
+ LeftHandSideExpression : OptionalExpression
+ 1. Return false.
+
+---*/
+$DONOTEVALUATE();
+
+for ([{
+ set y(val) {
+ throw new Test262Error('The property should not be accessed.');
+ }
+}?.y = 42] of [[23]]) ;
diff --git a/js/src/tests/test262/language/statements/for-of/dstr/array-elem-put-obj-literal-optchain-prop-ref.js b/js/src/tests/test262/language/statements/for-of/dstr/array-elem-put-obj-literal-optchain-prop-ref.js
new file mode 100644
index 0000000000..f15ea9f5e4
--- /dev/null
+++ b/js/src/tests/test262/language/statements/for-of/dstr/array-elem-put-obj-literal-optchain-prop-ref.js
@@ -0,0 +1,69 @@
+// |reftest| error:SyntaxError
+// This file was procedurally generated from the following sources:
+// - src/dstr-assignment/array-elem-put-obj-literal-optchain-prop-ref.case
+// - src/dstr-assignment/syntax/for-of.template
+/*---
+description: It is a Syntax Error if LeftHandSideExpression of an DestructuringAssignmentTarget is neither an ObjectLiteral nor an ArrayLiteral and AssignmentTargetType(LeftHandSideExpression) is not simple Using Object (For..of statement)
+esid: sec-for-in-and-for-of-statements-runtime-semantics-labelledevaluation
+features: [optional-chaining, destructuring-binding]
+flags: [generated]
+negative:
+ phase: parse
+ type: SyntaxError
+info: |
+ IterationStatement :
+ for ( LeftHandSideExpression of AssignmentExpression ) Statement
+
+ 1. Let keyResult be the result of performing ? ForIn/OfHeadEvaluation(« »,
+ AssignmentExpression, iterate).
+ 2. Return ? ForIn/OfBodyEvaluation(LeftHandSideExpression, Statement,
+ keyResult, assignment, labelSet).
+
+ 13.7.5.13 Runtime Semantics: ForIn/OfBodyEvaluation
+
+ [...]
+ 4. If destructuring is true and if lhsKind is assignment, then
+ a. Assert: lhs is a LeftHandSideExpression.
+ b. Let assignmentPattern be the parse of the source text corresponding to
+ lhs using AssignmentPattern as the goal symbol.
+ [...]
+
+ Syntax
+
+ AssignmentElement : DestructuringAssignmentTarget Initializer_opt
+ DestructuringAssignmentTarget : LeftHandSideExpression
+
+ Static Semantics: Early Errors
+
+ OptionalExpression:
+ MemberExpression OptionalChain
+ CallExpression OptionalChain
+ OptionalExpression OptionalChain
+
+ OptionalChain:
+ ?. [ Expression ]
+ ?. IdentifierName
+ ?. Arguments
+ ?. TemplateLiteral
+ OptionalChain [ Expression ]
+ OptionalChain .IdentifierName
+ OptionalChain Arguments
+ OptionalChain TemplateLiteral
+
+ DestructuringAssignmentTarget : LeftHandSideExpression
+
+ - It is a Syntax Error if LeftHandSideExpression is neither an ObjectLiteral nor an ArrayLiteral and IsValidSimpleAssignmentTarget(LeftHandSideExpression) is not true.
+
+ Static Semantics: IsValidSimpleAssignmentTarget
+
+ LeftHandSideExpression : OptionalExpression
+ 1. Return false.
+
+---*/
+$DONOTEVALUATE();
+
+for ([{
+ set y(val) {
+ throw new Test262Error('The property should not be accessed.');
+ }
+}?.y] of [[23]]) ;
diff --git a/js/src/tests/test262/language/statements/for-of/dstr/obj-prop-elem-target-memberexpr-optchain-prop-ref-init.js b/js/src/tests/test262/language/statements/for-of/dstr/obj-prop-elem-target-memberexpr-optchain-prop-ref-init.js
new file mode 100644
index 0000000000..92718cc184
--- /dev/null
+++ b/js/src/tests/test262/language/statements/for-of/dstr/obj-prop-elem-target-memberexpr-optchain-prop-ref-init.js
@@ -0,0 +1,66 @@
+// |reftest| error:SyntaxError
+// This file was procedurally generated from the following sources:
+// - src/dstr-assignment/obj-prop-elem-target-memberexpr-optchain-prop-ref-init.case
+// - src/dstr-assignment/syntax/for-of.template
+/*---
+description: It is a Syntax Error if LeftHandSideExpression of an DestructuringAssignmentTarget is neither an ObjectLiteral nor an ArrayLiteral and AssignmentTargetType(LeftHandSideExpression) is not simple Using Object (MemberExpression OptionalChain .IdentifierName Initializer) (For..of statement)
+esid: sec-for-in-and-for-of-statements-runtime-semantics-labelledevaluation
+features: [optional-chaining, destructuring-binding]
+flags: [generated]
+negative:
+ phase: parse
+ type: SyntaxError
+info: |
+ IterationStatement :
+ for ( LeftHandSideExpression of AssignmentExpression ) Statement
+
+ 1. Let keyResult be the result of performing ? ForIn/OfHeadEvaluation(« »,
+ AssignmentExpression, iterate).
+ 2. Return ? ForIn/OfBodyEvaluation(LeftHandSideExpression, Statement,
+ keyResult, assignment, labelSet).
+
+ 13.7.5.13 Runtime Semantics: ForIn/OfBodyEvaluation
+
+ [...]
+ 4. If destructuring is true and if lhsKind is assignment, then
+ a. Assert: lhs is a LeftHandSideExpression.
+ b. Let assignmentPattern be the parse of the source text corresponding to
+ lhs using AssignmentPattern as the goal symbol.
+ [...]
+
+ Syntax
+
+ AssignmentElement : DestructuringAssignmentTarget Initializer_opt
+ DestructuringAssignmentTarget : LeftHandSideExpression
+
+ Static Semantics: Early Errors
+
+ OptionalExpression:
+ MemberExpression OptionalChain
+ CallExpression OptionalChain
+ OptionalExpression OptionalChain
+
+ OptionalChain:
+ ?. [ Expression ]
+ ?. IdentifierName
+ ?. Arguments
+ ?. TemplateLiteral
+ OptionalChain [ Expression ]
+ OptionalChain .IdentifierName
+ OptionalChain Arguments
+ OptionalChain TemplateLiteral
+
+ DestructuringAssignmentTarget : LeftHandSideExpression
+
+ - It is a Syntax Error if LeftHandSideExpression is neither an ObjectLiteral nor an ArrayLiteral and IsValidSimpleAssignmentTarget(LeftHandSideExpression) is not true.
+
+ Static Semantics: IsValidSimpleAssignmentTarget
+
+ LeftHandSideExpression : OptionalExpression
+ 1. Return false.
+
+---*/
+$DONOTEVALUATE();
+var y = {};
+
+for ({ x: y?.z = 42 } of [{ x: 23 }]) ;
diff --git a/js/src/tests/test262/language/statements/for-of/dstr/obj-prop-elem-target-memberexpr-optchain-prop-ref.js b/js/src/tests/test262/language/statements/for-of/dstr/obj-prop-elem-target-memberexpr-optchain-prop-ref.js
new file mode 100644
index 0000000000..211d287a31
--- /dev/null
+++ b/js/src/tests/test262/language/statements/for-of/dstr/obj-prop-elem-target-memberexpr-optchain-prop-ref.js
@@ -0,0 +1,66 @@
+// |reftest| error:SyntaxError
+// This file was procedurally generated from the following sources:
+// - src/dstr-assignment/obj-prop-elem-target-memberexpr-optchain-prop-ref.case
+// - src/dstr-assignment/syntax/for-of.template
+/*---
+description: It is a Syntax Error if LeftHandSideExpression of an DestructuringAssignmentTarget is neither an ObjectLiteral nor an ArrayLiteral and AssignmentTargetType(LeftHandSideExpression) is not simple Using Object (MemberExpression OptionalChain .IdentifierName) (For..of statement)
+esid: sec-for-in-and-for-of-statements-runtime-semantics-labelledevaluation
+features: [optional-chaining, destructuring-binding]
+flags: [generated]
+negative:
+ phase: parse
+ type: SyntaxError
+info: |
+ IterationStatement :
+ for ( LeftHandSideExpression of AssignmentExpression ) Statement
+
+ 1. Let keyResult be the result of performing ? ForIn/OfHeadEvaluation(« »,
+ AssignmentExpression, iterate).
+ 2. Return ? ForIn/OfBodyEvaluation(LeftHandSideExpression, Statement,
+ keyResult, assignment, labelSet).
+
+ 13.7.5.13 Runtime Semantics: ForIn/OfBodyEvaluation
+
+ [...]
+ 4. If destructuring is true and if lhsKind is assignment, then
+ a. Assert: lhs is a LeftHandSideExpression.
+ b. Let assignmentPattern be the parse of the source text corresponding to
+ lhs using AssignmentPattern as the goal symbol.
+ [...]
+
+ Syntax
+
+ AssignmentElement : DestructuringAssignmentTarget Initializer_opt
+ DestructuringAssignmentTarget : LeftHandSideExpression
+
+ Static Semantics: Early Errors
+
+ OptionalExpression:
+ MemberExpression OptionalChain
+ CallExpression OptionalChain
+ OptionalExpression OptionalChain
+
+ OptionalChain:
+ ?. [ Expression ]
+ ?. IdentifierName
+ ?. Arguments
+ ?. TemplateLiteral
+ OptionalChain [ Expression ]
+ OptionalChain .IdentifierName
+ OptionalChain Arguments
+ OptionalChain TemplateLiteral
+
+ DestructuringAssignmentTarget : LeftHandSideExpression
+
+ - It is a Syntax Error if LeftHandSideExpression is neither an ObjectLiteral nor an ArrayLiteral and IsValidSimpleAssignmentTarget(LeftHandSideExpression) is not true.
+
+ Static Semantics: IsValidSimpleAssignmentTarget
+
+ LeftHandSideExpression : OptionalExpression
+ 1. Return false.
+
+---*/
+$DONOTEVALUATE();
+var y = {};
+
+for ({ x: y?.z } of [{ x: 23 }]) ;
diff --git a/js/src/tests/test262/language/statements/for-of/dstr/obj-prop-elem-target-obj-literal-optchain-prop-ref-init.js b/js/src/tests/test262/language/statements/for-of/dstr/obj-prop-elem-target-obj-literal-optchain-prop-ref-init.js
new file mode 100644
index 0000000000..630f73e9b0
--- /dev/null
+++ b/js/src/tests/test262/language/statements/for-of/dstr/obj-prop-elem-target-obj-literal-optchain-prop-ref-init.js
@@ -0,0 +1,69 @@
+// |reftest| error:SyntaxError
+// This file was procedurally generated from the following sources:
+// - src/dstr-assignment/obj-prop-elem-target-obj-literal-optchain-prop-ref-init.case
+// - src/dstr-assignment/syntax/for-of.template
+/*---
+description: It is a Syntax Error if LeftHandSideExpression of an DestructuringAssignmentTarget is neither an ObjectLiteral nor an ArrayLiteral and AssignmentTargetType(LeftHandSideExpression) is not simple Using Object (For..of statement)
+esid: sec-for-in-and-for-of-statements-runtime-semantics-labelledevaluation
+features: [optional-chaining, destructuring-binding]
+flags: [generated]
+negative:
+ phase: parse
+ type: SyntaxError
+info: |
+ IterationStatement :
+ for ( LeftHandSideExpression of AssignmentExpression ) Statement
+
+ 1. Let keyResult be the result of performing ? ForIn/OfHeadEvaluation(« »,
+ AssignmentExpression, iterate).
+ 2. Return ? ForIn/OfBodyEvaluation(LeftHandSideExpression, Statement,
+ keyResult, assignment, labelSet).
+
+ 13.7.5.13 Runtime Semantics: ForIn/OfBodyEvaluation
+
+ [...]
+ 4. If destructuring is true and if lhsKind is assignment, then
+ a. Assert: lhs is a LeftHandSideExpression.
+ b. Let assignmentPattern be the parse of the source text corresponding to
+ lhs using AssignmentPattern as the goal symbol.
+ [...]
+
+ Syntax
+
+ AssignmentElement : DestructuringAssignmentTarget Initializer_opt
+ DestructuringAssignmentTarget : LeftHandSideExpression
+
+ Static Semantics: Early Errors
+
+ OptionalExpression:
+ MemberExpression OptionalChain
+ CallExpression OptionalChain
+ OptionalExpression OptionalChain
+
+ OptionalChain:
+ ?. [ Expression ]
+ ?. IdentifierName
+ ?. Arguments
+ ?. TemplateLiteral
+ OptionalChain [ Expression ]
+ OptionalChain .IdentifierName
+ OptionalChain Arguments
+ OptionalChain TemplateLiteral
+
+ DestructuringAssignmentTarget : LeftHandSideExpression
+
+ - It is a Syntax Error if LeftHandSideExpression is neither an ObjectLiteral nor an ArrayLiteral and IsValidSimpleAssignmentTarget(LeftHandSideExpression) is not true.
+
+ Static Semantics: IsValidSimpleAssignmentTarget
+
+ LeftHandSideExpression : OptionalExpression
+ 1. Return false.
+
+---*/
+$DONOTEVALUATE();
+
+for ({ x: {
+ set y(val) {
+ throw new Test262Error('The property should not be accessed.');
+ }
+}?.y = 42} of [{x: 42}]) ;
diff --git a/js/src/tests/test262/language/statements/for-of/dstr/obj-prop-elem-target-obj-literal-optchain-prop-ref.js b/js/src/tests/test262/language/statements/for-of/dstr/obj-prop-elem-target-obj-literal-optchain-prop-ref.js
new file mode 100644
index 0000000000..b0c4d71776
--- /dev/null
+++ b/js/src/tests/test262/language/statements/for-of/dstr/obj-prop-elem-target-obj-literal-optchain-prop-ref.js
@@ -0,0 +1,69 @@
+// |reftest| error:SyntaxError
+// This file was procedurally generated from the following sources:
+// - src/dstr-assignment/obj-prop-elem-target-obj-literal-optchain-prop-ref.case
+// - src/dstr-assignment/syntax/for-of.template
+/*---
+description: It is a Syntax Error if LeftHandSideExpression of an DestructuringAssignmentTarget is neither an ObjectLiteral nor an ArrayLiteral and AssignmentTargetType(LeftHandSideExpression) is not simple Using Object (For..of statement)
+esid: sec-for-in-and-for-of-statements-runtime-semantics-labelledevaluation
+features: [optional-chaining, destructuring-binding]
+flags: [generated]
+negative:
+ phase: parse
+ type: SyntaxError
+info: |
+ IterationStatement :
+ for ( LeftHandSideExpression of AssignmentExpression ) Statement
+
+ 1. Let keyResult be the result of performing ? ForIn/OfHeadEvaluation(« »,
+ AssignmentExpression, iterate).
+ 2. Return ? ForIn/OfBodyEvaluation(LeftHandSideExpression, Statement,
+ keyResult, assignment, labelSet).
+
+ 13.7.5.13 Runtime Semantics: ForIn/OfBodyEvaluation
+
+ [...]
+ 4. If destructuring is true and if lhsKind is assignment, then
+ a. Assert: lhs is a LeftHandSideExpression.
+ b. Let assignmentPattern be the parse of the source text corresponding to
+ lhs using AssignmentPattern as the goal symbol.
+ [...]
+
+ Syntax
+
+ AssignmentElement : DestructuringAssignmentTarget Initializer_opt
+ DestructuringAssignmentTarget : LeftHandSideExpression
+
+ Static Semantics: Early Errors
+
+ OptionalExpression:
+ MemberExpression OptionalChain
+ CallExpression OptionalChain
+ OptionalExpression OptionalChain
+
+ OptionalChain:
+ ?. [ Expression ]
+ ?. IdentifierName
+ ?. Arguments
+ ?. TemplateLiteral
+ OptionalChain [ Expression ]
+ OptionalChain .IdentifierName
+ OptionalChain Arguments
+ OptionalChain TemplateLiteral
+
+ DestructuringAssignmentTarget : LeftHandSideExpression
+
+ - It is a Syntax Error if LeftHandSideExpression is neither an ObjectLiteral nor an ArrayLiteral and IsValidSimpleAssignmentTarget(LeftHandSideExpression) is not true.
+
+ Static Semantics: IsValidSimpleAssignmentTarget
+
+ LeftHandSideExpression : OptionalExpression
+ 1. Return false.
+
+---*/
+$DONOTEVALUATE();
+
+for ({ x: {
+ set y(val) {
+ throw new Test262Error('The property should not be accessed.');
+ }
+}?.y} of [{x: 42}]) ;
diff --git a/js/src/tests/test262/language/statements/for-of/dstr/shell.js b/js/src/tests/test262/language/statements/for-of/dstr/shell.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/language/statements/for-of/dstr/shell.js
diff --git a/js/src/tests/test262/language/statements/for-of/shell.js b/js/src/tests/test262/language/statements/for-of/shell.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/language/statements/for-of/shell.js
diff --git a/js/src/tests/test262/language/statements/shell.js b/js/src/tests/test262/language/statements/shell.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/language/statements/shell.js