Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions tsc/internal/transformers/estransforms/classfields.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
@@ -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() { };
Original file line number Diff line number Diff line change
@@ -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() { };
Loading
Loading