diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
commit | 26a029d407be480d791972afb5975cf62c9360a6 (patch) | |
tree | f435a8308119effd964b339f76abb83a57c29483 /js/src/tests/test262/language/expressions/optional-chaining | |
parent | Initial commit. (diff) | |
download | firefox-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')
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; |