summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMaximilian Goldstein <max.goldstein@qt.io>2021-04-09 15:03:20 +0200
committerMaximilian Goldstein <max.goldstein@qt.io>2021-04-13 11:45:16 +0000
commit4dad98d63c279b989fdb48006fbd1db8ee27bc7f (patch)
tree40bc5864e3df0edd9960b8acfdc769ff894a24ba
parent5a105134b9fdf9abc0dc12dc3e44027529634715 (diff)
downloadqtdeclarative-testsuites-snapshot-20180312-3c69133-based.tar.gz
Add optional chaining testssnapshot-20180312-3c69133-based
Change-Id: Ia87313a2756dfbc3d90128ac77cd4dc6c8c137df Reviewed-by: Ulf Hermann <ulf.hermann@qt.io> (cherry picked from commit 7d1cf05c547a636495b2731c4fc2842a01849064) Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
-rw-r--r--test/language/expressions/optional-chaining/call-expression-super-no-base.js23
-rw-r--r--test/language/expressions/optional-chaining/call-expression.js75
-rw-r--r--test/language/expressions/optional-chaining/early-errors-tail-position-null-op-template-string-esi.js25
-rw-r--r--test/language/expressions/optional-chaining/early-errors-tail-position-null-op-template-string.js22
-rw-r--r--test/language/expressions/optional-chaining/early-errors-tail-position-null-optchain-template-string-esi.js25
-rw-r--r--test/language/expressions/optional-chaining/early-errors-tail-position-null-optchain-template-string.js22
-rw-r--r--test/language/expressions/optional-chaining/early-errors-tail-position-op-template-string-esi.js27
-rw-r--r--test/language/expressions/optional-chaining/early-errors-tail-position-op-template-string.js24
-rw-r--r--test/language/expressions/optional-chaining/early-errors-tail-position-optchain-template-string-esi.js27
-rw-r--r--test/language/expressions/optional-chaining/early-errors-tail-position-optchain-template-string.js24
-rw-r--r--test/language/expressions/optional-chaining/eval-optional-call.js39
-rw-r--r--test/language/expressions/optional-chaining/iteration-statement-do.js18
-rw-r--r--test/language/expressions/optional-chaining/iteration-statement-for-await-of.js35
-rw-r--r--test/language/expressions/optional-chaining/iteration-statement-for-in.js22
-rw-r--r--test/language/expressions/optional-chaining/iteration-statement-for-of-type-error.js28
-rw-r--r--test/language/expressions/optional-chaining/iteration-statement-for.js43
-rw-r--r--test/language/expressions/optional-chaining/iteration-statement-while.js18
-rw-r--r--test/language/expressions/optional-chaining/member-expression-async-identifier.js32
-rw-r--r--test/language/expressions/optional-chaining/member-expression-async-literal.js19
-rw-r--r--test/language/expressions/optional-chaining/member-expression-async-this.js20
-rw-r--r--test/language/expressions/optional-chaining/member-expression.js104
-rw-r--r--test/language/expressions/optional-chaining/new-target-optional-call.js30
-rw-r--r--test/language/expressions/optional-chaining/optional-call-preserves-this.js27
-rw-r--r--test/language/expressions/optional-chaining/optional-chain-async-optional-chain-square-brackets.js28
-rw-r--r--test/language/expressions/optional-chaining/optional-chain-async-square-brackets.js24
-rw-r--r--test/language/expressions/optional-chaining/optional-chain-expression-optional-expression.js20
-rw-r--r--test/language/expressions/optional-chaining/optional-chain-prod-arguments.js19
-rw-r--r--test/language/expressions/optional-chaining/optional-chain-prod-expression.js42
-rw-r--r--test/language/expressions/optional-chaining/optional-chain-prod-identifiername.js38
-rw-r--r--test/language/expressions/optional-chaining/optional-chain.js50
-rw-r--r--test/language/expressions/optional-chaining/optional-expression.js27
-rw-r--r--test/language/expressions/optional-chaining/punctuator-decimal-lookahead.js15
-rw-r--r--test/language/expressions/optional-chaining/runtime-semantics-evaluation.js18
-rw-r--r--test/language/expressions/optional-chaining/short-circuiting.js22
-rw-r--r--test/language/expressions/optional-chaining/static-semantics-simple-assignment.js23
-rw-r--r--test/language/expressions/optional-chaining/super-property-optional-call.js30
-rw-r--r--test/language/expressions/optional-chaining/update-expression-postfix.js23
-rw-r--r--test/language/expressions/optional-chaining/update-expression-prefix.js23
38 files changed, 1131 insertions, 0 deletions
diff --git a/test/language/expressions/optional-chaining/call-expression-super-no-base.js b/test/language/expressions/optional-chaining/call-expression-super-no-base.js
new file mode 100644
index 000000000..c42cbf5e4
--- /dev/null
+++ b/test/language/expressions/optional-chaining/call-expression-super-no-base.js
@@ -0,0 +1,23 @@
+// 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:
+ type: SyntaxError
+ phase: parse
+---*/
+
+$DONOTEVALUATE();
+
+class C {
+ constructor () {
+ super()?.a;
+ }
+}
diff --git a/test/language/expressions/optional-chaining/call-expression.js b/test/language/expressions/optional-chaining/call-expression.js
new file mode 100644
index 000000000..4cc1a73fc
--- /dev/null
+++ b/test/language/expressions/optional-chaining/call-expression.js
@@ -0,0 +1,75 @@
+// 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);
diff --git a/test/language/expressions/optional-chaining/early-errors-tail-position-null-op-template-string-esi.js b/test/language/expressions/optional-chaining/early-errors-tail-position-null-op-template-string-esi.js
new file mode 100644
index 000000000..0a315116e
--- /dev/null
+++ b/test/language/expressions/optional-chaining/early-errors-tail-position-null-op-template-string-esi.js
@@ -0,0 +1,25 @@
+// 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:
+ type: SyntaxError
+ phase: parse
+---*/
+
+$DONOTEVALUATE();
+
+// This production exists in order to prevent automatic semicolon
+// insertion rules.
+null?.
+ `hello`
diff --git a/test/language/expressions/optional-chaining/early-errors-tail-position-null-op-template-string.js b/test/language/expressions/optional-chaining/early-errors-tail-position-null-op-template-string.js
new file mode 100644
index 000000000..1bf4f43cc
--- /dev/null
+++ b/test/language/expressions/optional-chaining/early-errors-tail-position-null-op-template-string.js
@@ -0,0 +1,22 @@
+// 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:
+ type: SyntaxError
+ phase: parse
+---*/
+
+$DONOTEVALUATE();
+
+null?.`hello`;
diff --git a/test/language/expressions/optional-chaining/early-errors-tail-position-null-optchain-template-string-esi.js b/test/language/expressions/optional-chaining/early-errors-tail-position-null-optchain-template-string-esi.js
new file mode 100644
index 000000000..897cf434f
--- /dev/null
+++ b/test/language/expressions/optional-chaining/early-errors-tail-position-null-optchain-template-string-esi.js
@@ -0,0 +1,25 @@
+// 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:
+ type: SyntaxError
+ phase: parse
+---*/
+
+$DONOTEVALUATE();
+
+// This production exists in order to prevent automatic semicolon
+// insertion rules.
+null?.fn
+ `hello`
diff --git a/test/language/expressions/optional-chaining/early-errors-tail-position-null-optchain-template-string.js b/test/language/expressions/optional-chaining/early-errors-tail-position-null-optchain-template-string.js
new file mode 100644
index 000000000..d59e71ee5
--- /dev/null
+++ b/test/language/expressions/optional-chaining/early-errors-tail-position-null-optchain-template-string.js
@@ -0,0 +1,22 @@
+// 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:
+ type: SyntaxError
+ phase: parse
+---*/
+
+$DONOTEVALUATE();
+
+null?.fn`hello`;
diff --git a/test/language/expressions/optional-chaining/early-errors-tail-position-op-template-string-esi.js b/test/language/expressions/optional-chaining/early-errors-tail-position-op-template-string-esi.js
new file mode 100644
index 000000000..82c9477f0
--- /dev/null
+++ b/test/language/expressions/optional-chaining/early-errors-tail-position-op-template-string-esi.js
@@ -0,0 +1,27 @@
+// 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:
+ type: SyntaxError
+ phase: parse
+---*/
+
+$DONOTEVALUATE();
+
+const a = function() {};
+
+// This production exists in order to prevent automatic semicolon
+// insertion rules.
+a?.
+ `hello`
diff --git a/test/language/expressions/optional-chaining/early-errors-tail-position-op-template-string.js b/test/language/expressions/optional-chaining/early-errors-tail-position-op-template-string.js
new file mode 100644
index 000000000..eaeffedfb
--- /dev/null
+++ b/test/language/expressions/optional-chaining/early-errors-tail-position-op-template-string.js
@@ -0,0 +1,24 @@
+// 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:
+ type: SyntaxError
+ phase: parse
+---*/
+
+$DONOTEVALUATE();
+
+const a = function() {};
+
+a?.`hello`;
diff --git a/test/language/expressions/optional-chaining/early-errors-tail-position-optchain-template-string-esi.js b/test/language/expressions/optional-chaining/early-errors-tail-position-optchain-template-string-esi.js
new file mode 100644
index 000000000..bbb98ea83
--- /dev/null
+++ b/test/language/expressions/optional-chaining/early-errors-tail-position-optchain-template-string-esi.js
@@ -0,0 +1,27 @@
+// 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:
+ type: SyntaxError
+ phase: parse
+---*/
+
+$DONOTEVALUATE();
+
+const a = {fn() {}};
+
+// This production exists in order to prevent automatic semicolon
+// insertion rules.
+a?.fn
+ `hello`
diff --git a/test/language/expressions/optional-chaining/early-errors-tail-position-optchain-template-string.js b/test/language/expressions/optional-chaining/early-errors-tail-position-optchain-template-string.js
new file mode 100644
index 000000000..302ac35cf
--- /dev/null
+++ b/test/language/expressions/optional-chaining/early-errors-tail-position-optchain-template-string.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: >
+ 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:
+ type: SyntaxError
+ phase: parse
+---*/
+
+$DONOTEVALUATE();
+
+const a = {fn() {}};
+
+a?.fn`hello`;
diff --git a/test/language/expressions/optional-chaining/eval-optional-call.js b/test/language/expressions/optional-chaining/eval-optional-call.js
new file mode 100644
index 000000000..3fa59bcbc
--- /dev/null
+++ b/test/language/expressions/optional-chaining/eval-optional-call.js
@@ -0,0 +1,39 @@
+// 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');
diff --git a/test/language/expressions/optional-chaining/iteration-statement-do.js b/test/language/expressions/optional-chaining/iteration-statement-do.js
new file mode 100644
index 000000000..5a82cc23c
--- /dev/null
+++ b/test/language/expressions/optional-chaining/iteration-statement-do.js
@@ -0,0 +1,18 @@
+// 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);
diff --git a/test/language/expressions/optional-chaining/iteration-statement-for-await-of.js b/test/language/expressions/optional-chaining/iteration-statement-for-await-of.js
new file mode 100644
index 000000000..6d414965a
--- /dev/null
+++ b/test/language/expressions/optional-chaining/iteration-statement-for-await-of.js
@@ -0,0 +1,35 @@
+// 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/test/language/expressions/optional-chaining/iteration-statement-for-in.js b/test/language/expressions/optional-chaining/iteration-statement-for-in.js
new file mode 100644
index 000000000..2823b8053
--- /dev/null
+++ b/test/language/expressions/optional-chaining/iteration-statement-for-in.js
@@ -0,0 +1,22 @@
+// 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);
diff --git a/test/language/expressions/optional-chaining/iteration-statement-for-of-type-error.js b/test/language/expressions/optional-chaining/iteration-statement-for-of-type-error.js
new file mode 100644
index 000000000..3cd18cd48
--- /dev/null
+++ b/test/language/expressions/optional-chaining/iteration-statement-for-of-type-error.js
@@ -0,0 +1,28 @@
+// 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);
+});
diff --git a/test/language/expressions/optional-chaining/iteration-statement-for.js b/test/language/expressions/optional-chaining/iteration-statement-for.js
new file mode 100644
index 000000000..c6d78a318
--- /dev/null
+++ b/test/language/expressions/optional-chaining/iteration-statement-for.js
@@ -0,0 +1,43 @@
+// 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);
diff --git a/test/language/expressions/optional-chaining/iteration-statement-while.js b/test/language/expressions/optional-chaining/iteration-statement-while.js
new file mode 100644
index 000000000..80fffa929
--- /dev/null
+++ b/test/language/expressions/optional-chaining/iteration-statement-while.js
@@ -0,0 +1,18 @@
+// 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);
diff --git a/test/language/expressions/optional-chaining/member-expression-async-identifier.js b/test/language/expressions/optional-chaining/member-expression-async-identifier.js
new file mode 100644
index 000000000..19f9385eb
--- /dev/null
+++ b/test/language/expressions/optional-chaining/member-expression-async-identifier.js
@@ -0,0 +1,32 @@
+// 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/test/language/expressions/optional-chaining/member-expression-async-literal.js b/test/language/expressions/optional-chaining/member-expression-async-literal.js
new file mode 100644
index 000000000..90cb7da02
--- /dev/null
+++ b/test/language/expressions/optional-chaining/member-expression-async-literal.js
@@ -0,0 +1,19 @@
+// 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/test/language/expressions/optional-chaining/member-expression-async-this.js b/test/language/expressions/optional-chaining/member-expression-async-this.js
new file mode 100644
index 000000000..988729a78
--- /dev/null
+++ b/test/language/expressions/optional-chaining/member-expression-async-this.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: >
+ 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/test/language/expressions/optional-chaining/member-expression.js b/test/language/expressions/optional-chaining/member-expression.js
new file mode 100644
index 000000000..0651d393e
--- /dev/null
+++ b/test/language/expressions/optional-chaining/member-expression.js
@@ -0,0 +1,104 @@
+// 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)); // Not available in ES7
+// AsyncGeneratorExpression
+// assert.sameValue('a', (async function * a () {}?.name)); // Not available in ES7
+// 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);
diff --git a/test/language/expressions/optional-chaining/new-target-optional-call.js b/test/language/expressions/optional-chaining/new-target-optional-call.js
new file mode 100644
index 000000000..aae31b9c0
--- /dev/null
+++ b/test/language/expressions/optional-chaining/new-target-optional-call.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 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);
diff --git a/test/language/expressions/optional-chaining/optional-call-preserves-this.js b/test/language/expressions/optional-chaining/optional-call-preserves-this.js
new file mode 100644
index 000000000..9e1eee629
--- /dev/null
+++ b/test/language/expressions/optional-chaining/optional-call-preserves-this.js
@@ -0,0 +1,27 @@
+// 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);
diff --git a/test/language/expressions/optional-chaining/optional-chain-async-optional-chain-square-brackets.js b/test/language/expressions/optional-chaining/optional-chain-async-optional-chain-square-brackets.js
new file mode 100644
index 000000000..5d64ad4d0
--- /dev/null
+++ b/test/language/expressions/optional-chaining/optional-chain-async-optional-chain-square-brackets.js
@@ -0,0 +1,28 @@
+// 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/test/language/expressions/optional-chaining/optional-chain-async-square-brackets.js b/test/language/expressions/optional-chaining/optional-chain-async-square-brackets.js
new file mode 100644
index 000000000..0930d2eaf
--- /dev/null
+++ b/test/language/expressions/optional-chaining/optional-chain-async-square-brackets.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: >
+ 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/test/language/expressions/optional-chaining/optional-chain-expression-optional-expression.js b/test/language/expressions/optional-chaining/optional-chain-expression-optional-expression.js
new file mode 100644
index 000000000..4391014d8
--- /dev/null
+++ b/test/language/expressions/optional-chaining/optional-chain-expression-optional-expression.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: >
+ 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]);
diff --git a/test/language/expressions/optional-chaining/optional-chain-prod-arguments.js b/test/language/expressions/optional-chaining/optional-chain-prod-arguments.js
new file mode 100644
index 000000000..c07fc57cb
--- /dev/null
+++ b/test/language/expressions/optional-chaining/optional-chain-prod-arguments.js
@@ -0,0 +1,19 @@
+// 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');
diff --git a/test/language/expressions/optional-chaining/optional-chain-prod-expression.js b/test/language/expressions/optional-chaining/optional-chain-prod-expression.js
new file mode 100644
index 000000000..bd9030584
--- /dev/null
+++ b/test/language/expressions/optional-chaining/optional-chain-prod-expression.js
@@ -0,0 +1,42 @@
+// 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]');
diff --git a/test/language/expressions/optional-chaining/optional-chain-prod-identifiername.js b/test/language/expressions/optional-chaining/optional-chain-prod-identifiername.js
new file mode 100644
index 000000000..768af6beb
--- /dev/null
+++ b/test/language/expressions/optional-chaining/optional-chain-prod-identifiername.js
@@ -0,0 +1,38 @@
+// 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);
diff --git a/test/language/expressions/optional-chaining/optional-chain.js b/test/language/expressions/optional-chaining/optional-chain.js
new file mode 100644
index 000000000..fed70c0c7
--- /dev/null
+++ b/test/language/expressions/optional-chaining/optional-chain.js
@@ -0,0 +1,50 @@
+// 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));
diff --git a/test/language/expressions/optional-chaining/optional-expression.js b/test/language/expressions/optional-chaining/optional-expression.js
new file mode 100644
index 000000000..86d41432b
--- /dev/null
+++ b/test/language/expressions/optional-chaining/optional-expression.js
@@ -0,0 +1,27 @@
+// 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);
diff --git a/test/language/expressions/optional-chaining/punctuator-decimal-lookahead.js b/test/language/expressions/optional-chaining/punctuator-decimal-lookahead.js
new file mode 100644
index 000000000..8cb007e45
--- /dev/null
+++ b/test/language/expressions/optional-chaining/punctuator-decimal-lookahead.js
@@ -0,0 +1,15 @@
+// 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);
diff --git a/test/language/expressions/optional-chaining/runtime-semantics-evaluation.js b/test/language/expressions/optional-chaining/runtime-semantics-evaluation.js
new file mode 100644
index 000000000..9062e2c5a
--- /dev/null
+++ b/test/language/expressions/optional-chaining/runtime-semantics-evaluation.js
@@ -0,0 +1,18 @@
+// 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);
diff --git a/test/language/expressions/optional-chaining/short-circuiting.js b/test/language/expressions/optional-chaining/short-circuiting.js
new file mode 100644
index 000000000..0b0a1e0d8
--- /dev/null
+++ b/test/language/expressions/optional-chaining/short-circuiting.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: >
+ 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);
diff --git a/test/language/expressions/optional-chaining/static-semantics-simple-assignment.js b/test/language/expressions/optional-chaining/static-semantics-simple-assignment.js
new file mode 100644
index 000000000..7eb974455
--- /dev/null
+++ b/test/language/expressions/optional-chaining/static-semantics-simple-assignment.js
@@ -0,0 +1,23 @@
+
+// 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:
+ type: SyntaxError
+ phase: parse
+---*/
+
+$DONOTEVALUATE();
+
+const obj = {};
+
+obj?.a = 33;
diff --git a/test/language/expressions/optional-chaining/super-property-optional-call.js b/test/language/expressions/optional-chaining/super-property-optional-call.js
new file mode 100644
index 000000000..cd572ade4
--- /dev/null
+++ b/test/language/expressions/optional-chaining/super-property-optional-call.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 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);
diff --git a/test/language/expressions/optional-chaining/update-expression-postfix.js b/test/language/expressions/optional-chaining/update-expression-postfix.js
new file mode 100644
index 000000000..b7a8e9e21
--- /dev/null
+++ b/test/language/expressions/optional-chaining/update-expression-postfix.js
@@ -0,0 +1,23 @@
+// 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:
+ type: SyntaxError
+ phase: parse
+---*/
+
+$DONOTEVALUATE();
+
+// LeftHandSideExpression ++
+const a = {};
+a?.b++;
diff --git a/test/language/expressions/optional-chaining/update-expression-prefix.js b/test/language/expressions/optional-chaining/update-expression-prefix.js
new file mode 100644
index 000000000..fb4b8ff8a
--- /dev/null
+++ b/test/language/expressions/optional-chaining/update-expression-prefix.js
@@ -0,0 +1,23 @@
+// 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:
+ type: SyntaxError
+ phase: parse
+---*/
+
+$DONOTEVALUATE();
+
+// --UnaryExpression
+const a = {};
+--a?.b;