Skip to content

Commit b6fed21

Browse files
authored
fix(53347): Incorrect generated JS code when private (hashtag) property is used with parenthesis in left assignment (microsoft#53434)
1 parent 2b57a88 commit b6fed21

File tree

5 files changed

+212
-3
lines changed

5 files changed

+212
-3
lines changed

src/compiler/transformers/classFields.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ import {
156156
nodeIsSynthesized,
157157
ObjectLiteralElement,
158158
OmittedExpression,
159+
OuterExpressionKinds,
159160
ParameterDeclaration,
160161
ParenthesizedExpression,
161162
PartiallyEmittedExpression,
@@ -1489,13 +1490,14 @@ export function transformClassFields(context: TransformationContext): (x: Source
14891490
return factory.updateBinaryExpression(node, left, node.operatorToken, right);
14901491
}
14911492

1492-
if (isPrivateIdentifierPropertyAccessExpression(node.left)) {
1493+
const left = skipOuterExpressions(node.left, OuterExpressionKinds.PartiallyEmittedExpressions | OuterExpressionKinds.Parentheses);
1494+
if (isPrivateIdentifierPropertyAccessExpression(left)) {
14931495
// obj.#x = ...
1494-
const info = accessPrivateIdentifier(node.left.name);
1496+
const info = accessPrivateIdentifier(left.name);
14951497
if (info) {
14961498
return setTextRange(
14971499
setOriginalNode(
1498-
createPrivateIdentifierAssignment(info, node.left.expression, node.right, node.operatorToken.kind),
1500+
createPrivateIdentifierAssignment(info, left.expression, node.right, node.operatorToken.kind),
14991501
node
15001502
),
15011503
node
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
//// [privateNameFieldParenthesisLeftAssignment.ts]
2+
class Foo {
3+
#p: number;
4+
5+
constructor(value: number) {
6+
this.#p = value;
7+
}
8+
9+
t1(p: number) {
10+
(this.#p as number) = p;
11+
}
12+
13+
t2(p: number) {
14+
(((this.#p as number))) = p;
15+
}
16+
17+
t3(p: number) {
18+
(this.#p) = p;
19+
}
20+
21+
t4(p: number) {
22+
(((this.#p))) = p;
23+
}
24+
}
25+
26+
27+
//// [privateNameFieldParenthesisLeftAssignment.js]
28+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
29+
if (kind === "m") throw new TypeError("Private method is not writable");
30+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
31+
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");
32+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
33+
};
34+
var _Foo_p;
35+
class Foo {
36+
constructor(value) {
37+
_Foo_p.set(this, void 0);
38+
__classPrivateFieldSet(this, _Foo_p, value, "f");
39+
}
40+
t1(p) {
41+
__classPrivateFieldSet(this, _Foo_p, p, "f");
42+
}
43+
t2(p) {
44+
__classPrivateFieldSet(this, _Foo_p, p, "f");
45+
}
46+
t3(p) {
47+
__classPrivateFieldSet(this, _Foo_p, p, "f");
48+
}
49+
t4(p) {
50+
__classPrivateFieldSet(this, _Foo_p, p, "f");
51+
}
52+
}
53+
_Foo_p = new WeakMap();
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
=== tests/cases/conformance/classes/members/privateNames/privateNameFieldParenthesisLeftAssignment.ts ===
2+
class Foo {
3+
>Foo : Symbol(Foo, Decl(privateNameFieldParenthesisLeftAssignment.ts, 0, 0))
4+
5+
#p: number;
6+
>#p : Symbol(Foo.#p, Decl(privateNameFieldParenthesisLeftAssignment.ts, 0, 11))
7+
8+
constructor(value: number) {
9+
>value : Symbol(value, Decl(privateNameFieldParenthesisLeftAssignment.ts, 3, 16))
10+
11+
this.#p = value;
12+
>this.#p : Symbol(Foo.#p, Decl(privateNameFieldParenthesisLeftAssignment.ts, 0, 11))
13+
>this : Symbol(Foo, Decl(privateNameFieldParenthesisLeftAssignment.ts, 0, 0))
14+
>value : Symbol(value, Decl(privateNameFieldParenthesisLeftAssignment.ts, 3, 16))
15+
}
16+
17+
t1(p: number) {
18+
>t1 : Symbol(Foo.t1, Decl(privateNameFieldParenthesisLeftAssignment.ts, 5, 5))
19+
>p : Symbol(p, Decl(privateNameFieldParenthesisLeftAssignment.ts, 7, 7))
20+
21+
(this.#p as number) = p;
22+
>this.#p : Symbol(Foo.#p, Decl(privateNameFieldParenthesisLeftAssignment.ts, 0, 11))
23+
>this : Symbol(Foo, Decl(privateNameFieldParenthesisLeftAssignment.ts, 0, 0))
24+
>p : Symbol(p, Decl(privateNameFieldParenthesisLeftAssignment.ts, 7, 7))
25+
}
26+
27+
t2(p: number) {
28+
>t2 : Symbol(Foo.t2, Decl(privateNameFieldParenthesisLeftAssignment.ts, 9, 5))
29+
>p : Symbol(p, Decl(privateNameFieldParenthesisLeftAssignment.ts, 11, 7))
30+
31+
(((this.#p as number))) = p;
32+
>this.#p : Symbol(Foo.#p, Decl(privateNameFieldParenthesisLeftAssignment.ts, 0, 11))
33+
>this : Symbol(Foo, Decl(privateNameFieldParenthesisLeftAssignment.ts, 0, 0))
34+
>p : Symbol(p, Decl(privateNameFieldParenthesisLeftAssignment.ts, 11, 7))
35+
}
36+
37+
t3(p: number) {
38+
>t3 : Symbol(Foo.t3, Decl(privateNameFieldParenthesisLeftAssignment.ts, 13, 5))
39+
>p : Symbol(p, Decl(privateNameFieldParenthesisLeftAssignment.ts, 15, 7))
40+
41+
(this.#p) = p;
42+
>this.#p : Symbol(Foo.#p, Decl(privateNameFieldParenthesisLeftAssignment.ts, 0, 11))
43+
>this : Symbol(Foo, Decl(privateNameFieldParenthesisLeftAssignment.ts, 0, 0))
44+
>p : Symbol(p, Decl(privateNameFieldParenthesisLeftAssignment.ts, 15, 7))
45+
}
46+
47+
t4(p: number) {
48+
>t4 : Symbol(Foo.t4, Decl(privateNameFieldParenthesisLeftAssignment.ts, 17, 5))
49+
>p : Symbol(p, Decl(privateNameFieldParenthesisLeftAssignment.ts, 19, 7))
50+
51+
(((this.#p))) = p;
52+
>this.#p : Symbol(Foo.#p, Decl(privateNameFieldParenthesisLeftAssignment.ts, 0, 11))
53+
>this : Symbol(Foo, Decl(privateNameFieldParenthesisLeftAssignment.ts, 0, 0))
54+
>p : Symbol(p, Decl(privateNameFieldParenthesisLeftAssignment.ts, 19, 7))
55+
}
56+
}
57+
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
=== tests/cases/conformance/classes/members/privateNames/privateNameFieldParenthesisLeftAssignment.ts ===
2+
class Foo {
3+
>Foo : Foo
4+
5+
#p: number;
6+
>#p : number
7+
8+
constructor(value: number) {
9+
>value : number
10+
11+
this.#p = value;
12+
>this.#p = value : number
13+
>this.#p : number
14+
>this : this
15+
>value : number
16+
}
17+
18+
t1(p: number) {
19+
>t1 : (p: number) => void
20+
>p : number
21+
22+
(this.#p as number) = p;
23+
>(this.#p as number) = p : number
24+
>(this.#p as number) : number
25+
>this.#p as number : number
26+
>this.#p : number
27+
>this : this
28+
>p : number
29+
}
30+
31+
t2(p: number) {
32+
>t2 : (p: number) => void
33+
>p : number
34+
35+
(((this.#p as number))) = p;
36+
>(((this.#p as number))) = p : number
37+
>(((this.#p as number))) : number
38+
>((this.#p as number)) : number
39+
>(this.#p as number) : number
40+
>this.#p as number : number
41+
>this.#p : number
42+
>this : this
43+
>p : number
44+
}
45+
46+
t3(p: number) {
47+
>t3 : (p: number) => void
48+
>p : number
49+
50+
(this.#p) = p;
51+
>(this.#p) = p : number
52+
>(this.#p) : number
53+
>this.#p : number
54+
>this : this
55+
>p : number
56+
}
57+
58+
t4(p: number) {
59+
>t4 : (p: number) => void
60+
>p : number
61+
62+
(((this.#p))) = p;
63+
>(((this.#p))) = p : number
64+
>(((this.#p))) : number
65+
>((this.#p)) : number
66+
>(this.#p) : number
67+
>this.#p : number
68+
>this : this
69+
>p : number
70+
}
71+
}
72+
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// @target: es2015
2+
3+
class Foo {
4+
#p: number;
5+
6+
constructor(value: number) {
7+
this.#p = value;
8+
}
9+
10+
t1(p: number) {
11+
(this.#p as number) = p;
12+
}
13+
14+
t2(p: number) {
15+
(((this.#p as number))) = p;
16+
}
17+
18+
t3(p: number) {
19+
(this.#p) = p;
20+
}
21+
22+
t4(p: number) {
23+
(((this.#p))) = p;
24+
}
25+
}

0 commit comments

Comments
 (0)