diff --git a/tsc/internal/transformers/estransforms/classfields.go b/tsc/internal/transformers/estransforms/classfields.go index c8ec805df9060..729a4f63f8cc4 100644 --- a/tsc/internal/transformers/estransforms/classfields.go +++ b/tsc/internal/transformers/estransforms/classfields.go @@ -1626,6 +1626,19 @@ func (tx *classFieldsTransformer) visitParenthesizedExpression(node *ast.Parenth func (tx *classFieldsTransformer) createPrivateIdentifierAssignment(info *privateIdentifierInfo, receiver *ast.Expression, right *ast.Expression, operator ast.Kind) *ast.Expression { receiver = tx.Visitor().VisitNode(receiver) + if ast.IsLogicalOrCoalescingAssignmentOperator(operator) { + readExpression, initializeExpression := tx.createCopiableReceiverExpr(receiver) + if initializeExpression == nil { + initializeExpression = readExpression + } + return tx.Factory().NewBinaryExpression( + nil, + tx.createPrivateIdentifierAccessHelper(info, initializeExpression), + nil, + tx.Factory().NewToken(transformers.GetNonAssignmentOperatorForCompoundAssignment(operator)), + tx.createPrivateIdentifierAssignment(info, readExpression, right, ast.KindEqualsToken), + ) + } right = tx.Visitor().VisitNode(right) if ast.IsCompoundAssignment(operator) { diff --git a/tsc/testdata/baselines/reference/compiler/privateAccessorLogicalAssignment(target=es2015).js b/tsc/testdata/baselines/reference/compiler/privateAccessorLogicalAssignment(target=es2015).js new file mode 100644 index 0000000000000..0d51649ed1e78 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/privateAccessorLogicalAssignment(target=es2015).js @@ -0,0 +1,171 @@ +//// [tests/cases/compiler/privateAccessorLogicalAssignment.ts] //// + +//// [privateAccessorLogicalAssignment.ts] +const log: string[] = []; +function rhs() { + log.push("rhs"); + return 2; +} + +class C { + value: number | null | undefined = 0; + get #f() { + log.push("get"); + return this.value; + } + set #f(value: number | null | undefined) { + log.push("set " + value); + this.value = value; + } + and() { + return this.#f &&= rhs(); + } + or() { + return (this.#f) ||= rhs(); + } + coalesce() { + return (this.#f as number | null | undefined) ??= rhs(); + } + static and(receiver: () => C) { + return receiver().#f &&= rhs(); + } + static or(receiver: () => C) { + return receiver().#f ||= rhs(); + } + static coalesce(receiver: () => C) { + return receiver().#f ??= rhs(); + } + static andIdentifier(receiver: C) { + return receiver.#f &&= rhs(); + } +} + +class S { + static value: number | null | undefined = 0; + static get #f() { + log.push("get"); + return this.value; + } + static set #f(value: number | null | undefined) { + log.push("set " + value); + this.value = value; + } + static and() { + return this.#f &&= rhs(); + } + static or() { + return this.#f ||= rhs(); + } + static coalesce() { + return this.#f ??= rhs(); + } +} + +class ReadOnly { + get #f() { return 0; } + #m() {} + run() { + // @ts-expect-error + this.#f &&= rhs(); + // @ts-expect-error + this.#m ||= rhs(); + // @ts-expect-error + this.#m ??= rhs(); + } +} + + +//// [privateAccessorLogicalAssignment.js] +"use strict"; +var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { + if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); + if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); + return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); +}; +var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { + if (kind === "m") throw new TypeError("Private method is not writable"); + if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); + if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); + return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; +}; +var _C_instances, _C_f_get, _C_f_set, _a, _S_f_get, _S_f_set, _ReadOnly_instances, _ReadOnly_f_get, _ReadOnly_m; +const log = []; +function rhs() { + log.push("rhs"); + return 2; +} +class C { + constructor() { + _C_instances.add(this); + this.value = 0; + } + and() { + return __classPrivateFieldGet(this, _C_instances, "a", _C_f_get) && __classPrivateFieldSet(this, _C_instances, rhs(), "a", _C_f_set); + } + or() { + return __classPrivateFieldGet(this, _C_instances, "a", _C_f_get) || __classPrivateFieldSet(this, _C_instances, rhs(), "a", _C_f_set); + } + coalesce() { + var _b; + return (_b = __classPrivateFieldGet(this, _C_instances, "a", _C_f_get)) !== null && _b !== void 0 ? _b : __classPrivateFieldSet(this, _C_instances, rhs(), "a", _C_f_set); + } + static and(receiver) { + var _b; + return __classPrivateFieldGet(_b = receiver(), _C_instances, "a", _C_f_get) && __classPrivateFieldSet(_b, _C_instances, rhs(), "a", _C_f_set); + } + static or(receiver) { + var _b; + return __classPrivateFieldGet(_b = receiver(), _C_instances, "a", _C_f_get) || __classPrivateFieldSet(_b, _C_instances, rhs(), "a", _C_f_set); + } + static coalesce(receiver) { + var _b; + var _c; + return (_b = __classPrivateFieldGet(_c = receiver(), _C_instances, "a", _C_f_get)) !== null && _b !== void 0 ? _b : __classPrivateFieldSet(_c, _C_instances, rhs(), "a", _C_f_set); + } + static andIdentifier(receiver) { + var _b; + return __classPrivateFieldGet(_b = receiver, _C_instances, "a", _C_f_get) && __classPrivateFieldSet(_b, _C_instances, rhs(), "a", _C_f_set); + } +} +_C_instances = new WeakSet(), _C_f_get = function _C_f_get() { + log.push("get"); + return this.value; +}, _C_f_set = function _C_f_set(value) { + log.push("set " + value); + this.value = value; +}; +class S { + static and() { + return __classPrivateFieldGet(this, _a, "a", _S_f_get) && __classPrivateFieldSet(this, _a, rhs(), "a", _S_f_set); + } + static or() { + return __classPrivateFieldGet(this, _a, "a", _S_f_get) || __classPrivateFieldSet(this, _a, rhs(), "a", _S_f_set); + } + static coalesce() { + var _b; + return (_b = __classPrivateFieldGet(this, _a, "a", _S_f_get)) !== null && _b !== void 0 ? _b : __classPrivateFieldSet(this, _a, rhs(), "a", _S_f_set); + } +} +_a = S, _S_f_get = function _S_f_get() { + log.push("get"); + return this.value; +}, _S_f_set = function _S_f_set(value) { + log.push("set " + value); + this.value = value; +}; +S.value = 0; +class ReadOnly { + constructor() { + _ReadOnly_instances.add(this); + } + run() { + var _b; + // @ts-expect-error + __classPrivateFieldGet(this, _ReadOnly_instances, "a", _ReadOnly_f_get) && __classPrivateFieldSet(this, _ReadOnly_instances, rhs(), "a"); + // @ts-expect-error + __classPrivateFieldGet(this, _ReadOnly_instances, "m", _ReadOnly_m) || __classPrivateFieldSet(this, _ReadOnly_instances, rhs(), "m"); + // @ts-expect-error + (_b = __classPrivateFieldGet(this, _ReadOnly_instances, "m", _ReadOnly_m)) !== null && _b !== void 0 ? _b : __classPrivateFieldSet(this, _ReadOnly_instances, rhs(), "m"); + } +} +_ReadOnly_instances = new WeakSet(), _ReadOnly_f_get = function _ReadOnly_f_get() { return 0; }, _ReadOnly_m = function _ReadOnly_m() { }; diff --git a/tsc/testdata/baselines/reference/compiler/privateAccessorLogicalAssignment(target=es2020).js b/tsc/testdata/baselines/reference/compiler/privateAccessorLogicalAssignment(target=es2020).js new file mode 100644 index 0000000000000..f87f9baaea7fd --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/privateAccessorLogicalAssignment(target=es2020).js @@ -0,0 +1,167 @@ +//// [tests/cases/compiler/privateAccessorLogicalAssignment.ts] //// + +//// [privateAccessorLogicalAssignment.ts] +const log: string[] = []; +function rhs() { + log.push("rhs"); + return 2; +} + +class C { + value: number | null | undefined = 0; + get #f() { + log.push("get"); + return this.value; + } + set #f(value: number | null | undefined) { + log.push("set " + value); + this.value = value; + } + and() { + return this.#f &&= rhs(); + } + or() { + return (this.#f) ||= rhs(); + } + coalesce() { + return (this.#f as number | null | undefined) ??= rhs(); + } + static and(receiver: () => C) { + return receiver().#f &&= rhs(); + } + static or(receiver: () => C) { + return receiver().#f ||= rhs(); + } + static coalesce(receiver: () => C) { + return receiver().#f ??= rhs(); + } + static andIdentifier(receiver: C) { + return receiver.#f &&= rhs(); + } +} + +class S { + static value: number | null | undefined = 0; + static get #f() { + log.push("get"); + return this.value; + } + static set #f(value: number | null | undefined) { + log.push("set " + value); + this.value = value; + } + static and() { + return this.#f &&= rhs(); + } + static or() { + return this.#f ||= rhs(); + } + static coalesce() { + return this.#f ??= rhs(); + } +} + +class ReadOnly { + get #f() { return 0; } + #m() {} + run() { + // @ts-expect-error + this.#f &&= rhs(); + // @ts-expect-error + this.#m ||= rhs(); + // @ts-expect-error + this.#m ??= rhs(); + } +} + + +//// [privateAccessorLogicalAssignment.js] +"use strict"; +var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { + if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); + if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); + return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); +}; +var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { + if (kind === "m") throw new TypeError("Private method is not writable"); + if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); + if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); + return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; +}; +var _C_instances, _C_f_get, _C_f_set, _a, _S_f_get, _S_f_set, _ReadOnly_instances, _ReadOnly_f_get, _ReadOnly_m; +const log = []; +function rhs() { + log.push("rhs"); + return 2; +} +class C { + constructor() { + _C_instances.add(this); + this.value = 0; + } + and() { + return __classPrivateFieldGet(this, _C_instances, "a", _C_f_get) && __classPrivateFieldSet(this, _C_instances, rhs(), "a", _C_f_set); + } + or() { + return __classPrivateFieldGet(this, _C_instances, "a", _C_f_get) || __classPrivateFieldSet(this, _C_instances, rhs(), "a", _C_f_set); + } + coalesce() { + return __classPrivateFieldGet(this, _C_instances, "a", _C_f_get) ?? __classPrivateFieldSet(this, _C_instances, rhs(), "a", _C_f_set); + } + static and(receiver) { + var _b; + return __classPrivateFieldGet(_b = receiver(), _C_instances, "a", _C_f_get) && __classPrivateFieldSet(_b, _C_instances, rhs(), "a", _C_f_set); + } + static or(receiver) { + var _b; + return __classPrivateFieldGet(_b = receiver(), _C_instances, "a", _C_f_get) || __classPrivateFieldSet(_b, _C_instances, rhs(), "a", _C_f_set); + } + static coalesce(receiver) { + var _b; + return __classPrivateFieldGet(_b = receiver(), _C_instances, "a", _C_f_get) ?? __classPrivateFieldSet(_b, _C_instances, rhs(), "a", _C_f_set); + } + static andIdentifier(receiver) { + var _b; + return __classPrivateFieldGet(_b = receiver, _C_instances, "a", _C_f_get) && __classPrivateFieldSet(_b, _C_instances, rhs(), "a", _C_f_set); + } +} +_C_instances = new WeakSet(), _C_f_get = function _C_f_get() { + log.push("get"); + return this.value; +}, _C_f_set = function _C_f_set(value) { + log.push("set " + value); + this.value = value; +}; +class S { + static and() { + return __classPrivateFieldGet(this, _a, "a", _S_f_get) && __classPrivateFieldSet(this, _a, rhs(), "a", _S_f_set); + } + static or() { + return __classPrivateFieldGet(this, _a, "a", _S_f_get) || __classPrivateFieldSet(this, _a, rhs(), "a", _S_f_set); + } + static coalesce() { + return __classPrivateFieldGet(this, _a, "a", _S_f_get) ?? __classPrivateFieldSet(this, _a, rhs(), "a", _S_f_set); + } +} +_a = S, _S_f_get = function _S_f_get() { + log.push("get"); + return this.value; +}, _S_f_set = function _S_f_set(value) { + log.push("set " + value); + this.value = value; +}; +S.value = 0; +class ReadOnly { + constructor() { + _ReadOnly_instances.add(this); + } + run() { + // @ts-expect-error + __classPrivateFieldGet(this, _ReadOnly_instances, "a", _ReadOnly_f_get) && __classPrivateFieldSet(this, _ReadOnly_instances, rhs(), "a"); + // @ts-expect-error + __classPrivateFieldGet(this, _ReadOnly_instances, "m", _ReadOnly_m) || __classPrivateFieldSet(this, _ReadOnly_instances, rhs(), "m"); + // @ts-expect-error + __classPrivateFieldGet(this, _ReadOnly_instances, "m", _ReadOnly_m) ?? __classPrivateFieldSet(this, _ReadOnly_instances, rhs(), "m"); + } +} +_ReadOnly_instances = new WeakSet(), _ReadOnly_f_get = function _ReadOnly_f_get() { return 0; }, _ReadOnly_m = function _ReadOnly_m() { }; diff --git a/tsc/testdata/baselines/reference/compiler/privateAccessorLogicalAssignment(target=es2021).js b/tsc/testdata/baselines/reference/compiler/privateAccessorLogicalAssignment(target=es2021).js new file mode 100644 index 0000000000000..f87f9baaea7fd --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/privateAccessorLogicalAssignment(target=es2021).js @@ -0,0 +1,167 @@ +//// [tests/cases/compiler/privateAccessorLogicalAssignment.ts] //// + +//// [privateAccessorLogicalAssignment.ts] +const log: string[] = []; +function rhs() { + log.push("rhs"); + return 2; +} + +class C { + value: number | null | undefined = 0; + get #f() { + log.push("get"); + return this.value; + } + set #f(value: number | null | undefined) { + log.push("set " + value); + this.value = value; + } + and() { + return this.#f &&= rhs(); + } + or() { + return (this.#f) ||= rhs(); + } + coalesce() { + return (this.#f as number | null | undefined) ??= rhs(); + } + static and(receiver: () => C) { + return receiver().#f &&= rhs(); + } + static or(receiver: () => C) { + return receiver().#f ||= rhs(); + } + static coalesce(receiver: () => C) { + return receiver().#f ??= rhs(); + } + static andIdentifier(receiver: C) { + return receiver.#f &&= rhs(); + } +} + +class S { + static value: number | null | undefined = 0; + static get #f() { + log.push("get"); + return this.value; + } + static set #f(value: number | null | undefined) { + log.push("set " + value); + this.value = value; + } + static and() { + return this.#f &&= rhs(); + } + static or() { + return this.#f ||= rhs(); + } + static coalesce() { + return this.#f ??= rhs(); + } +} + +class ReadOnly { + get #f() { return 0; } + #m() {} + run() { + // @ts-expect-error + this.#f &&= rhs(); + // @ts-expect-error + this.#m ||= rhs(); + // @ts-expect-error + this.#m ??= rhs(); + } +} + + +//// [privateAccessorLogicalAssignment.js] +"use strict"; +var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { + if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); + if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); + return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); +}; +var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { + if (kind === "m") throw new TypeError("Private method is not writable"); + if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); + if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); + return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; +}; +var _C_instances, _C_f_get, _C_f_set, _a, _S_f_get, _S_f_set, _ReadOnly_instances, _ReadOnly_f_get, _ReadOnly_m; +const log = []; +function rhs() { + log.push("rhs"); + return 2; +} +class C { + constructor() { + _C_instances.add(this); + this.value = 0; + } + and() { + return __classPrivateFieldGet(this, _C_instances, "a", _C_f_get) && __classPrivateFieldSet(this, _C_instances, rhs(), "a", _C_f_set); + } + or() { + return __classPrivateFieldGet(this, _C_instances, "a", _C_f_get) || __classPrivateFieldSet(this, _C_instances, rhs(), "a", _C_f_set); + } + coalesce() { + return __classPrivateFieldGet(this, _C_instances, "a", _C_f_get) ?? __classPrivateFieldSet(this, _C_instances, rhs(), "a", _C_f_set); + } + static and(receiver) { + var _b; + return __classPrivateFieldGet(_b = receiver(), _C_instances, "a", _C_f_get) && __classPrivateFieldSet(_b, _C_instances, rhs(), "a", _C_f_set); + } + static or(receiver) { + var _b; + return __classPrivateFieldGet(_b = receiver(), _C_instances, "a", _C_f_get) || __classPrivateFieldSet(_b, _C_instances, rhs(), "a", _C_f_set); + } + static coalesce(receiver) { + var _b; + return __classPrivateFieldGet(_b = receiver(), _C_instances, "a", _C_f_get) ?? __classPrivateFieldSet(_b, _C_instances, rhs(), "a", _C_f_set); + } + static andIdentifier(receiver) { + var _b; + return __classPrivateFieldGet(_b = receiver, _C_instances, "a", _C_f_get) && __classPrivateFieldSet(_b, _C_instances, rhs(), "a", _C_f_set); + } +} +_C_instances = new WeakSet(), _C_f_get = function _C_f_get() { + log.push("get"); + return this.value; +}, _C_f_set = function _C_f_set(value) { + log.push("set " + value); + this.value = value; +}; +class S { + static and() { + return __classPrivateFieldGet(this, _a, "a", _S_f_get) && __classPrivateFieldSet(this, _a, rhs(), "a", _S_f_set); + } + static or() { + return __classPrivateFieldGet(this, _a, "a", _S_f_get) || __classPrivateFieldSet(this, _a, rhs(), "a", _S_f_set); + } + static coalesce() { + return __classPrivateFieldGet(this, _a, "a", _S_f_get) ?? __classPrivateFieldSet(this, _a, rhs(), "a", _S_f_set); + } +} +_a = S, _S_f_get = function _S_f_get() { + log.push("get"); + return this.value; +}, _S_f_set = function _S_f_set(value) { + log.push("set " + value); + this.value = value; +}; +S.value = 0; +class ReadOnly { + constructor() { + _ReadOnly_instances.add(this); + } + run() { + // @ts-expect-error + __classPrivateFieldGet(this, _ReadOnly_instances, "a", _ReadOnly_f_get) && __classPrivateFieldSet(this, _ReadOnly_instances, rhs(), "a"); + // @ts-expect-error + __classPrivateFieldGet(this, _ReadOnly_instances, "m", _ReadOnly_m) || __classPrivateFieldSet(this, _ReadOnly_instances, rhs(), "m"); + // @ts-expect-error + __classPrivateFieldGet(this, _ReadOnly_instances, "m", _ReadOnly_m) ?? __classPrivateFieldSet(this, _ReadOnly_instances, rhs(), "m"); + } +} +_ReadOnly_instances = new WeakSet(), _ReadOnly_f_get = function _ReadOnly_f_get() { return 0; }, _ReadOnly_m = function _ReadOnly_m() { }; diff --git a/tsc/testdata/baselines/reference/compiler/privateAccessorLogicalAssignment(target=es2022).js b/tsc/testdata/baselines/reference/compiler/privateAccessorLogicalAssignment(target=es2022).js new file mode 100644 index 0000000000000..78902f72aa04c --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/privateAccessorLogicalAssignment(target=es2022).js @@ -0,0 +1,148 @@ +//// [tests/cases/compiler/privateAccessorLogicalAssignment.ts] //// + +//// [privateAccessorLogicalAssignment.ts] +const log: string[] = []; +function rhs() { + log.push("rhs"); + return 2; +} + +class C { + value: number | null | undefined = 0; + get #f() { + log.push("get"); + return this.value; + } + set #f(value: number | null | undefined) { + log.push("set " + value); + this.value = value; + } + and() { + return this.#f &&= rhs(); + } + or() { + return (this.#f) ||= rhs(); + } + coalesce() { + return (this.#f as number | null | undefined) ??= rhs(); + } + static and(receiver: () => C) { + return receiver().#f &&= rhs(); + } + static or(receiver: () => C) { + return receiver().#f ||= rhs(); + } + static coalesce(receiver: () => C) { + return receiver().#f ??= rhs(); + } + static andIdentifier(receiver: C) { + return receiver.#f &&= rhs(); + } +} + +class S { + static value: number | null | undefined = 0; + static get #f() { + log.push("get"); + return this.value; + } + static set #f(value: number | null | undefined) { + log.push("set " + value); + this.value = value; + } + static and() { + return this.#f &&= rhs(); + } + static or() { + return this.#f ||= rhs(); + } + static coalesce() { + return this.#f ??= rhs(); + } +} + +class ReadOnly { + get #f() { return 0; } + #m() {} + run() { + // @ts-expect-error + this.#f &&= rhs(); + // @ts-expect-error + this.#m ||= rhs(); + // @ts-expect-error + this.#m ??= rhs(); + } +} + + +//// [privateAccessorLogicalAssignment.js] +"use strict"; +const log = []; +function rhs() { + log.push("rhs"); + return 2; +} +class C { + value = 0; + get #f() { + log.push("get"); + return this.value; + } + set #f(value) { + log.push("set " + value); + this.value = value; + } + and() { + return this.#f &&= rhs(); + } + or() { + return (this.#f) ||= rhs(); + } + coalesce() { + return this.#f ??= rhs(); + } + static and(receiver) { + return receiver().#f &&= rhs(); + } + static or(receiver) { + return receiver().#f ||= rhs(); + } + static coalesce(receiver) { + return receiver().#f ??= rhs(); + } + static andIdentifier(receiver) { + return receiver.#f &&= rhs(); + } +} +class S { + static value = 0; + static get #f() { + log.push("get"); + return this.value; + } + static set #f(value) { + log.push("set " + value); + this.value = value; + } + static and() { + return this.#f &&= rhs(); + } + static or() { + return this.#f ||= rhs(); + } + static coalesce() { + return this.#f ??= rhs(); + } +} +class ReadOnly { + get #f() { return 0; } + #m() { } + run() { + // @ts-expect-error + this.#f &&= rhs(); + // @ts-expect-error + this.#m ||= rhs(); + // @ts-expect-error + this.#m ??= rhs(); + } +} diff --git a/tsc/testdata/baselines/reference/conformance/nullishCoalescingAssignmentVsPrivateFieldsJsEmit1.js b/tsc/testdata/baselines/reference/conformance/nullishCoalescingAssignmentVsPrivateFieldsJsEmit1.js index 27c295f342667..38da795a04798 100644 --- a/tsc/testdata/baselines/reference/conformance/nullishCoalescingAssignmentVsPrivateFieldsJsEmit1.js +++ b/tsc/testdata/baselines/reference/conformance/nullishCoalescingAssignmentVsPrivateFieldsJsEmit1.js @@ -36,7 +36,7 @@ class Cls { _Cls_privateProp.set(this, void 0); } problem() { - __classPrivateFieldSet(this, _Cls_privateProp, __classPrivateFieldGet(this, _Cls_privateProp, "f") ?? (false ? neverThis() : 20), "f"); + __classPrivateFieldGet(this, _Cls_privateProp, "f") ?? __classPrivateFieldSet(this, _Cls_privateProp, false ? neverThis() : 20, "f"); } } _Cls_privateProp = new WeakMap(); diff --git a/tsc/testdata/tests/cases/compiler/privateAccessorLogicalAssignment.ts b/tsc/testdata/tests/cases/compiler/privateAccessorLogicalAssignment.ts new file mode 100644 index 0000000000000..d98964625cbd5 --- /dev/null +++ b/tsc/testdata/tests/cases/compiler/privateAccessorLogicalAssignment.ts @@ -0,0 +1,76 @@ +// @strict: true +// @target: es2015, es2020, es2021, es2022 +// @noTypesAndSymbols: true + +const log: string[] = []; +function rhs() { + log.push("rhs"); + return 2; +} + +class C { + value: number | null | undefined = 0; + get #f() { + log.push("get"); + return this.value; + } + set #f(value: number | null | undefined) { + log.push("set " + value); + this.value = value; + } + and() { + return this.#f &&= rhs(); + } + or() { + return (this.#f) ||= rhs(); + } + coalesce() { + return (this.#f as number | null | undefined) ??= rhs(); + } + static and(receiver: () => C) { + return receiver().#f &&= rhs(); + } + static or(receiver: () => C) { + return receiver().#f ||= rhs(); + } + static coalesce(receiver: () => C) { + return receiver().#f ??= rhs(); + } + static andIdentifier(receiver: C) { + return receiver.#f &&= rhs(); + } +} + +class S { + static value: number | null | undefined = 0; + static get #f() { + log.push("get"); + return this.value; + } + static set #f(value: number | null | undefined) { + log.push("set " + value); + this.value = value; + } + static and() { + return this.#f &&= rhs(); + } + static or() { + return this.#f ||= rhs(); + } + static coalesce() { + return this.#f ??= rhs(); + } +} + +class ReadOnly { + get #f() { return 0; } + #m() {} + run() { + // @ts-expect-error + this.#f &&= rhs(); + // @ts-expect-error + this.#m ||= rhs(); + // @ts-expect-error + this.#m ??= rhs(); + } +}