From 8f3aba3024901a8559ace6f4e3de6b168ac13406 Mon Sep 17 00:00:00 2001 From: "Benjamin E. Coe" Date: Mon, 12 Aug 2019 21:48:50 -0700 Subject: [PATCH] test: continuing to flesh out optional chaining tests (#2272) --- .../call-expression-super-no-base.js | 23 ++++ .../optional-chaining/call-expression.js | 59 ++++++++- .../optional-chaining/member-expression.js | 116 +++++++++++++----- .../optional-chaining/optional-chain.js | 50 ++++++++ .../optional-chaining/optional-expression.js | 8 +- .../update-expression-postfix.js | 23 ++++ .../update-expression-prefix.js | 23 ++++ 7 files changed, 262 insertions(+), 40 deletions(-) create mode 100644 test/language/expressions/optional-chaining/call-expression-super-no-base.js create mode 100644 test/language/expressions/optional-chaining/optional-chain.js create mode 100644 test/language/expressions/optional-chaining/update-expression-postfix.js create mode 100644 test/language/expressions/optional-chaining/update-expression-prefix.js 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 0000000000..c42cbf5e4b --- /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 index fe8317c965..b23e2b34ac 100644 --- a/test/language/expressions/optional-chaining/call-expression.js +++ b/test/language/expressions/optional-chaining/call-expression.js @@ -11,10 +11,65 @@ info: | features: [optional-chaining] ---*/ +// CallExpression CoverCallExpressionAndAsyncArrowHead function fn () { return {a: 33}; }; - -// CallExpression Arguments +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/member-expression.js b/test/language/expressions/optional-chaining/member-expression.js index 93fcf2931a..1ed0b93b62 100644 --- a/test/language/expressions/optional-chaining/member-expression.js +++ b/test/language/expressions/optional-chaining/member-expression.js @@ -13,44 +13,92 @@ features: [optional-chaining] // PrimaryExpression // IdentifierReference - -const arr = [10, 11]; -const fn = (arg1, arg2) => { - return arg1 + arg2; +const a = {b: 22}; +assert.sameValue(22, a?.b); +// this +function fn () { + return this?.a } -const i = 0; -const obj = { - a: 'hello', - b: {val: 13}, - c(arg1) { - return arg1 * 2; - }, - arr: [11, 12] -}; +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); -// OptionalChain: ?.[Expression] -assert.sameValue(11, arr?.[i + 1]); +// MemberExpression [ Expression ] +const arr = [{a: 33}]; +assert.sameValue(33, arr[0]?.a); +assert.sameValue(undefined, arr[1]?.a); -// OptionalChain: ?.IdentifierName -assert.sameValue('hello', obj?.a); +// MemberExpression .IdentifierName +const obj = {a: {b: 44}}; +assert.sameValue(44, obj.a?.b); +assert.sameValue(undefined, obj.c?.b); -// OptionalChain: ?.Arguments -assert.sameValue(30, fn?.(10, 20)); +// MemberExpression TemplateLiteral +function f2 () { + return {a: 33}; +} +function f3 () {} +assert.sameValue(33, f2`hello world`?.a); +assert.sameValue(undefined, f3`hello world`?.a); -// OptionalChain: OptionalChain [Expression] -assert.sameValue(12, obj?.arr[i + 1]); -assert.throws(TypeError, function() { - obj?.d[i + 1]; -}); +// 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()); -// OptionalChain: OptionalChain .IdentifierName -assert.sameValue(13, obj?.b.val); -assert.throws(TypeError, function() { - obj?.d.e; -}); +// MemberExpression MetaProperty +class C { + constructor () { + assert.sameValue(undefined, new.target?.a); + } +} +new C(); -// OptionalChain: OptionalChain Arguments -assert.sameValue(20, obj?.c(10)); -assert.throws(TypeError, function() { - obj?.d(); -}); +// 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/optional-chain.js b/test/language/expressions/optional-chaining/optional-chain.js new file mode 100644 index 0000000000..fed70c0c72 --- /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 index eb9026557a..86d41432b4 100644 --- a/test/language/expressions/optional-chaining/optional-expression.js +++ b/test/language/expressions/optional-chaining/optional-expression.js @@ -21,7 +21,7 @@ function fn () { return {}; } -// MemberExpression -assert.sameValue(22, (obj?.a)?.b); -// CallExpression -assert.sameValue(undefined, (fn()?.a)?.b); +// 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/update-expression-postfix.js b/test/language/expressions/optional-chaining/update-expression-postfix.js new file mode 100644 index 0000000000..b7a8e9e212 --- /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 0000000000..fb4b8ff8a8 --- /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;