summaryrefslogtreecommitdiffstats
path: root/js/src/tests/test262/language/expressions/optional-chaining
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /js/src/tests/test262/language/expressions/optional-chaining
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'js/src/tests/test262/language/expressions/optional-chaining')
-rw-r--r--js/src/tests/test262/language/expressions/optional-chaining/browser.js0
-rw-r--r--js/src/tests/test262/language/expressions/optional-chaining/call-expression-super-no-base.js24
-rw-r--r--js/src/tests/test262/language/expressions/optional-chaining/call-expression.js77
-rw-r--r--js/src/tests/test262/language/expressions/optional-chaining/early-errors-tail-position-null-op-template-string-esi.js26
-rw-r--r--js/src/tests/test262/language/expressions/optional-chaining/early-errors-tail-position-null-op-template-string.js23
-rw-r--r--js/src/tests/test262/language/expressions/optional-chaining/early-errors-tail-position-null-optchain-template-string-esi.js26
-rw-r--r--js/src/tests/test262/language/expressions/optional-chaining/early-errors-tail-position-null-optchain-template-string.js23
-rw-r--r--js/src/tests/test262/language/expressions/optional-chaining/early-errors-tail-position-op-template-string-esi.js28
-rw-r--r--js/src/tests/test262/language/expressions/optional-chaining/early-errors-tail-position-op-template-string.js25
-rw-r--r--js/src/tests/test262/language/expressions/optional-chaining/early-errors-tail-position-optchain-template-string-esi.js28
-rw-r--r--js/src/tests/test262/language/expressions/optional-chaining/early-errors-tail-position-optchain-template-string.js25
-rw-r--r--js/src/tests/test262/language/expressions/optional-chaining/eval-optional-call.js41
-rw-r--r--js/src/tests/test262/language/expressions/optional-chaining/iteration-statement-do.js20
-rw-r--r--js/src/tests/test262/language/expressions/optional-chaining/iteration-statement-for-await-of.js37
-rw-r--r--js/src/tests/test262/language/expressions/optional-chaining/iteration-statement-for-in.js24
-rw-r--r--js/src/tests/test262/language/expressions/optional-chaining/iteration-statement-for-of-type-error.js30
-rw-r--r--js/src/tests/test262/language/expressions/optional-chaining/iteration-statement-for.js45
-rw-r--r--js/src/tests/test262/language/expressions/optional-chaining/iteration-statement-while.js20
-rw-r--r--js/src/tests/test262/language/expressions/optional-chaining/member-expression-async-identifier.js34
-rw-r--r--js/src/tests/test262/language/expressions/optional-chaining/member-expression-async-literal.js21
-rw-r--r--js/src/tests/test262/language/expressions/optional-chaining/member-expression-async-this.js21
-rw-r--r--js/src/tests/test262/language/expressions/optional-chaining/member-expression.js106
-rw-r--r--js/src/tests/test262/language/expressions/optional-chaining/new-target-optional-call.js32
-rw-r--r--js/src/tests/test262/language/expressions/optional-chaining/optional-call-preserves-this.js29
-rw-r--r--js/src/tests/test262/language/expressions/optional-chaining/optional-chain-async-optional-chain-square-brackets.js30
-rw-r--r--js/src/tests/test262/language/expressions/optional-chaining/optional-chain-async-square-brackets.js26
-rw-r--r--js/src/tests/test262/language/expressions/optional-chaining/optional-chain-expression-optional-expression.js22
-rw-r--r--js/src/tests/test262/language/expressions/optional-chaining/optional-chain-prod-arguments.js21
-rw-r--r--js/src/tests/test262/language/expressions/optional-chaining/optional-chain-prod-expression.js44
-rw-r--r--js/src/tests/test262/language/expressions/optional-chaining/optional-chain-prod-identifiername.js40
-rw-r--r--js/src/tests/test262/language/expressions/optional-chaining/optional-chain.js52
-rw-r--r--js/src/tests/test262/language/expressions/optional-chaining/optional-expression.js29
-rw-r--r--js/src/tests/test262/language/expressions/optional-chaining/punctuator-decimal-lookahead.js17
-rw-r--r--js/src/tests/test262/language/expressions/optional-chaining/runtime-semantics-evaluation.js20
-rw-r--r--js/src/tests/test262/language/expressions/optional-chaining/shell.js113
-rw-r--r--js/src/tests/test262/language/expressions/optional-chaining/short-circuiting.js24
-rw-r--r--js/src/tests/test262/language/expressions/optional-chaining/static-semantics-simple-assignment.js24
-rw-r--r--js/src/tests/test262/language/expressions/optional-chaining/super-property-optional-call.js32
-rw-r--r--js/src/tests/test262/language/expressions/optional-chaining/update-expression-postfix.js24
-rw-r--r--js/src/tests/test262/language/expressions/optional-chaining/update-expression-prefix.js24
40 files changed, 1307 insertions, 0 deletions
diff --git a/js/src/tests/test262/language/expressions/optional-chaining/browser.js b/js/src/tests/test262/language/expressions/optional-chaining/browser.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/language/expressions/optional-chaining/browser.js
diff --git a/js/src/tests/test262/language/expressions/optional-chaining/call-expression-super-no-base.js b/js/src/tests/test262/language/expressions/optional-chaining/call-expression-super-no-base.js
new file mode 100644
index 0000000000..da3a634bdf
--- /dev/null
+++ b/js/src/tests/test262/language/expressions/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/expressions/optional-chaining/call-expression.js b/js/src/tests/test262/language/expressions/optional-chaining/call-expression.js
new file mode 100644
index 0000000000..aa3f4abeb5
--- /dev/null
+++ b/js/src/tests/test262/language/expressions/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/expressions/optional-chaining/early-errors-tail-position-null-op-template-string-esi.js b/js/src/tests/test262/language/expressions/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/expressions/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/expressions/optional-chaining/early-errors-tail-position-null-op-template-string.js b/js/src/tests/test262/language/expressions/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/expressions/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/expressions/optional-chaining/early-errors-tail-position-null-optchain-template-string-esi.js b/js/src/tests/test262/language/expressions/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/expressions/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/expressions/optional-chaining/early-errors-tail-position-null-optchain-template-string.js b/js/src/tests/test262/language/expressions/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/expressions/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/expressions/optional-chaining/early-errors-tail-position-op-template-string-esi.js b/js/src/tests/test262/language/expressions/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/expressions/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/expressions/optional-chaining/early-errors-tail-position-op-template-string.js b/js/src/tests/test262/language/expressions/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/expressions/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/expressions/optional-chaining/early-errors-tail-position-optchain-template-string-esi.js b/js/src/tests/test262/language/expressions/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/expressions/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/expressions/optional-chaining/early-errors-tail-position-optchain-template-string.js b/js/src/tests/test262/language/expressions/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/expressions/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/expressions/optional-chaining/eval-optional-call.js b/js/src/tests/test262/language/expressions/optional-chaining/eval-optional-call.js
new file mode 100644
index 0000000000..8ff4800560
--- /dev/null
+++ b/js/src/tests/test262/language/expressions/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/expressions/optional-chaining/iteration-statement-do.js b/js/src/tests/test262/language/expressions/optional-chaining/iteration-statement-do.js
new file mode 100644
index 0000000000..470f067b20
--- /dev/null
+++ b/js/src/tests/test262/language/expressions/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/expressions/optional-chaining/iteration-statement-for-await-of.js b/js/src/tests/test262/language/expressions/optional-chaining/iteration-statement-for-await-of.js
new file mode 100644
index 0000000000..ec799bf2d3
--- /dev/null
+++ b/js/src/tests/test262/language/expressions/optional-chaining/iteration-statement-for-await-of.js
@@ -0,0 +1,37 @@
+// |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]
+includes: [asyncHelpers.js]
+---*/
+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);
+}
+asyncTest(checkAssertions);
diff --git a/js/src/tests/test262/language/expressions/optional-chaining/iteration-statement-for-in.js b/js/src/tests/test262/language/expressions/optional-chaining/iteration-statement-for-in.js
new file mode 100644
index 0000000000..6774675f1e
--- /dev/null
+++ b/js/src/tests/test262/language/expressions/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/expressions/optional-chaining/iteration-statement-for-of-type-error.js b/js/src/tests/test262/language/expressions/optional-chaining/iteration-statement-for-of-type-error.js
new file mode 100644
index 0000000000..938e10d8d4
--- /dev/null
+++ b/js/src/tests/test262/language/expressions/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/expressions/optional-chaining/iteration-statement-for.js b/js/src/tests/test262/language/expressions/optional-chaining/iteration-statement-for.js
new file mode 100644
index 0000000000..cb884d486e
--- /dev/null
+++ b/js/src/tests/test262/language/expressions/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/expressions/optional-chaining/iteration-statement-while.js b/js/src/tests/test262/language/expressions/optional-chaining/iteration-statement-while.js
new file mode 100644
index 0000000000..1390315896
--- /dev/null
+++ b/js/src/tests/test262/language/expressions/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/expressions/optional-chaining/member-expression-async-identifier.js b/js/src/tests/test262/language/expressions/optional-chaining/member-expression-async-identifier.js
new file mode 100644
index 0000000000..deffd0b9ae
--- /dev/null
+++ b/js/src/tests/test262/language/expressions/optional-chaining/member-expression-async-identifier.js
@@ -0,0 +1,34 @@
+// |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]
+includes: [asyncHelpers.js]
+---*/
+
+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');
+}
+asyncTest(checkAssertions);
diff --git a/js/src/tests/test262/language/expressions/optional-chaining/member-expression-async-literal.js b/js/src/tests/test262/language/expressions/optional-chaining/member-expression-async-literal.js
new file mode 100644
index 0000000000..00e791f916
--- /dev/null
+++ b/js/src/tests/test262/language/expressions/optional-chaining/member-expression-async-literal.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 literal] OptionalChain
+features: [optional-chaining]
+flags: [async]
+includes: [asyncHelpers.js]
+---*/
+
+async function checkAssertions() {
+ assert.sameValue(await "hello"?.[0], 'h');
+ assert.sameValue(await null?.a, undefined);
+}
+asyncTest(checkAssertions);
diff --git a/js/src/tests/test262/language/expressions/optional-chaining/member-expression-async-this.js b/js/src/tests/test262/language/expressions/optional-chaining/member-expression-async-this.js
new file mode 100644
index 0000000000..5de87fa9bb
--- /dev/null
+++ b/js/src/tests/test262/language/expressions/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/expressions/optional-chaining/member-expression.js b/js/src/tests/test262/language/expressions/optional-chaining/member-expression.js
new file mode 100644
index 0000000000..4854182c75
--- /dev/null
+++ b/js/src/tests/test262/language/expressions/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/expressions/optional-chaining/new-target-optional-call.js b/js/src/tests/test262/language/expressions/optional-chaining/new-target-optional-call.js
new file mode 100644
index 0000000000..df05a11507
--- /dev/null
+++ b/js/src/tests/test262/language/expressions/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/expressions/optional-chaining/optional-call-preserves-this.js b/js/src/tests/test262/language/expressions/optional-chaining/optional-call-preserves-this.js
new file mode 100644
index 0000000000..dbaf92c3b9
--- /dev/null
+++ b/js/src/tests/test262/language/expressions/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/expressions/optional-chaining/optional-chain-async-optional-chain-square-brackets.js b/js/src/tests/test262/language/expressions/optional-chaining/optional-chain-async-optional-chain-square-brackets.js
new file mode 100644
index 0000000000..1acd866b23
--- /dev/null
+++ b/js/src/tests/test262/language/expressions/optional-chaining/optional-chain-async-optional-chain-square-brackets.js
@@ -0,0 +1,30 @@
+// |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]
+includes: [asyncHelpers.js]
+---*/
+
+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);
+}
+asyncTest(checkAssertions);
diff --git a/js/src/tests/test262/language/expressions/optional-chaining/optional-chain-async-square-brackets.js b/js/src/tests/test262/language/expressions/optional-chaining/optional-chain-async-square-brackets.js
new file mode 100644
index 0000000000..361b324295
--- /dev/null
+++ b/js/src/tests/test262/language/expressions/optional-chaining/optional-chain-async-square-brackets.js
@@ -0,0 +1,26 @@
+// |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]
+includes: [asyncHelpers.js]
+---*/
+
+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);
+}
+asyncTest(checkAssertions);
diff --git a/js/src/tests/test262/language/expressions/optional-chaining/optional-chain-expression-optional-expression.js b/js/src/tests/test262/language/expressions/optional-chaining/optional-chain-expression-optional-expression.js
new file mode 100644
index 0000000000..be898b876e
--- /dev/null
+++ b/js/src/tests/test262/language/expressions/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/expressions/optional-chaining/optional-chain-prod-arguments.js b/js/src/tests/test262/language/expressions/optional-chaining/optional-chain-prod-arguments.js
new file mode 100644
index 0000000000..c9d9874078
--- /dev/null
+++ b/js/src/tests/test262/language/expressions/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/expressions/optional-chaining/optional-chain-prod-expression.js b/js/src/tests/test262/language/expressions/optional-chaining/optional-chain-prod-expression.js
new file mode 100644
index 0000000000..dfde4d26c2
--- /dev/null
+++ b/js/src/tests/test262/language/expressions/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/expressions/optional-chaining/optional-chain-prod-identifiername.js b/js/src/tests/test262/language/expressions/optional-chaining/optional-chain-prod-identifiername.js
new file mode 100644
index 0000000000..2636caf315
--- /dev/null
+++ b/js/src/tests/test262/language/expressions/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/expressions/optional-chaining/optional-chain.js b/js/src/tests/test262/language/expressions/optional-chaining/optional-chain.js
new file mode 100644
index 0000000000..b8dd183092
--- /dev/null
+++ b/js/src/tests/test262/language/expressions/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/expressions/optional-chaining/optional-expression.js b/js/src/tests/test262/language/expressions/optional-chaining/optional-expression.js
new file mode 100644
index 0000000000..38cba72d21
--- /dev/null
+++ b/js/src/tests/test262/language/expressions/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/expressions/optional-chaining/punctuator-decimal-lookahead.js b/js/src/tests/test262/language/expressions/optional-chaining/punctuator-decimal-lookahead.js
new file mode 100644
index 0000000000..ec64f9201e
--- /dev/null
+++ b/js/src/tests/test262/language/expressions/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/expressions/optional-chaining/runtime-semantics-evaluation.js b/js/src/tests/test262/language/expressions/optional-chaining/runtime-semantics-evaluation.js
new file mode 100644
index 0000000000..a87af57856
--- /dev/null
+++ b/js/src/tests/test262/language/expressions/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/expressions/optional-chaining/shell.js b/js/src/tests/test262/language/expressions/optional-chaining/shell.js
new file mode 100644
index 0000000000..ae18ad584d
--- /dev/null
+++ b/js/src/tests/test262/language/expressions/optional-chaining/shell.js
@@ -0,0 +1,113 @@
+// GENERATED, DO NOT EDIT
+// file: asyncHelpers.js
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+description: |
+ A collection of assertion and wrapper functions for testing asynchronous built-ins.
+defines: [asyncTest]
+---*/
+
+function asyncTest(testFunc) {
+ if (!Object.hasOwn(globalThis, "$DONE")) {
+ throw new Test262Error("asyncTest called without async flag");
+ }
+ if (typeof testFunc !== "function") {
+ $DONE(new Test262Error("asyncTest called with non-function argument"));
+ return;
+ }
+ try {
+ testFunc().then(
+ function () {
+ $DONE();
+ },
+ function (error) {
+ $DONE(error);
+ }
+ );
+ } catch (syncError) {
+ $DONE(syncError);
+ }
+}
+
+assert.throwsAsync = async function (expectedErrorConstructor, func, message) {
+ var innerThenable;
+ if (message === undefined) {
+ message = "";
+ } else {
+ message += " ";
+ }
+ if (typeof func === "function") {
+ try {
+ innerThenable = func();
+ if (
+ innerThenable === null ||
+ typeof innerThenable !== "object" ||
+ typeof innerThenable.then !== "function"
+ ) {
+ message +=
+ "Expected to obtain an inner promise that would reject with a" +
+ expectedErrorConstructor.name +
+ " but result was not a thenable";
+ throw new Test262Error(message);
+ }
+ } catch (thrown) {
+ message +=
+ "Expected a " +
+ expectedErrorConstructor.name +
+ " to be thrown asynchronously but an exception was thrown synchronously while obtaining the inner promise";
+ throw new Test262Error(message);
+ }
+ } else {
+ message +=
+ "assert.throwsAsync called with an argument that is not a function";
+ throw new Test262Error(message);
+ }
+
+ try {
+ return innerThenable.then(
+ function () {
+ message +=
+ "Expected a " +
+ expectedErrorConstructor.name +
+ " to be thrown asynchronously but no exception was thrown at all";
+ throw new Test262Error(message);
+ },
+ function (thrown) {
+ var expectedName, actualName;
+ if (typeof thrown !== "object" || thrown === null) {
+ message += "Thrown value was not an object!";
+ throw new Test262Error(message);
+ } else if (thrown.constructor !== expectedErrorConstructor) {
+ expectedName = expectedErrorConstructor.name;
+ actualName = thrown.constructor.name;
+ if (expectedName === actualName) {
+ message +=
+ "Expected a " +
+ expectedName +
+ " but got a different error constructor with the same name";
+ } else {
+ message +=
+ "Expected a " + expectedName + " but got a " + actualName;
+ }
+ throw new Test262Error(message);
+ }
+ }
+ );
+ } catch (thrown) {
+ if (typeof thrown !== "object" || thrown === null) {
+ message +=
+ "Expected a " +
+ expectedErrorConstructor.name +
+ " to be thrown asynchronously but innerThenable synchronously threw a value that was not an object ";
+ } else {
+ message +=
+ "Expected a " +
+ expectedErrorConstructor.name +
+ " to be thrown asynchronously but a " +
+ thrown.constructor.name +
+ " was thrown synchronously";
+ }
+ throw new Test262Error(message);
+ }
+};
diff --git a/js/src/tests/test262/language/expressions/optional-chaining/short-circuiting.js b/js/src/tests/test262/language/expressions/optional-chaining/short-circuiting.js
new file mode 100644
index 0000000000..74295cb1ee
--- /dev/null
+++ b/js/src/tests/test262/language/expressions/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/expressions/optional-chaining/static-semantics-simple-assignment.js b/js/src/tests/test262/language/expressions/optional-chaining/static-semantics-simple-assignment.js
new file mode 100644
index 0000000000..cbbcedba50
--- /dev/null
+++ b/js/src/tests/test262/language/expressions/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/expressions/optional-chaining/super-property-optional-call.js b/js/src/tests/test262/language/expressions/optional-chaining/super-property-optional-call.js
new file mode 100644
index 0000000000..21d1635ecc
--- /dev/null
+++ b/js/src/tests/test262/language/expressions/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/expressions/optional-chaining/update-expression-postfix.js b/js/src/tests/test262/language/expressions/optional-chaining/update-expression-postfix.js
new file mode 100644
index 0000000000..8b8fc68f9a
--- /dev/null
+++ b/js/src/tests/test262/language/expressions/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/expressions/optional-chaining/update-expression-prefix.js b/js/src/tests/test262/language/expressions/optional-chaining/update-expression-prefix.js
new file mode 100644
index 0000000000..ba65aadc0c
--- /dev/null
+++ b/js/src/tests/test262/language/expressions/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;