Skip to content

Commit e2bc2bc

Browse files
Preserve single evaluation of wrapped compound assignment targets (#65297)
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: RyanCavanaugh <6685088+RyanCavanaugh@users.noreply.github.com>
1 parent ce8b744 commit e2bc2bc

8 files changed

Lines changed: 729 additions & 36 deletions

‎tsc/internal/transformers/estransforms/exponentiation.go‎

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,17 +34,25 @@ func (ch *exponentiationTransformer) visitBinaryExpression(node *ast.BinaryExpre
3434
func (ch *exponentiationTransformer) visitExponentiationAssignmentExpression(node *ast.BinaryExpression) *ast.Node {
3535
var target *ast.Node
3636
var value *ast.Node
37-
left := ch.Visitor().VisitNode(node.Left)
37+
left := ast.SkipOuterExpressions(ch.Visitor().VisitNode(node.Left), ast.OEKParentheses|ast.OEKPartiallyEmittedExpressions)
3838
right := ch.Visitor().VisitNode(node.Right)
39+
var expressionTemp *ast.Node
40+
var objExpr *ast.Node
41+
if ast.IsAccessExpression(left) {
42+
expressionTemp = left.Expression()
43+
objExpr = expressionTemp
44+
if expressionTemp.Kind != ast.KindSuperKeyword {
45+
expressionTemp = ch.Factory().NewTempVariable()
46+
ch.EmitContext().AddVariableDeclaration(expressionTemp)
47+
objExpr = ch.Factory().NewAssignmentExpression(expressionTemp, left.Expression())
48+
objExpr.Loc = left.Expression().Loc
49+
}
50+
}
3951
if ast.IsElementAccessExpression(left) {
4052
// Transforms `a[x] **= b` into `(_a = a)[_x = x] = Math.pow(_a[_x], b)`
41-
expressionTemp := ch.Factory().NewTempVariable()
42-
ch.EmitContext().AddVariableDeclaration(expressionTemp)
4353
argumentExpressionTemp := ch.Factory().NewTempVariable()
4454
ch.EmitContext().AddVariableDeclaration(argumentExpressionTemp)
4555

46-
objExpr := ch.Factory().NewAssignmentExpression(expressionTemp, left.Expression())
47-
objExpr.Loc = left.Expression().Loc
4856
accessExpr := ch.Factory().NewAssignmentExpression(argumentExpressionTemp, left.AsElementAccessExpression().ArgumentExpression)
4957
accessExpr.Loc = left.AsElementAccessExpression().ArgumentExpression.Loc
5058

@@ -54,11 +62,7 @@ func (ch *exponentiationTransformer) visitExponentiationAssignmentExpression(nod
5462
value.Loc = left.Loc
5563
} else if ast.IsPropertyAccessExpression(left) {
5664
// Transforms `a.x **= b` into `(_a = a).x = Math.pow(_a.x, b)`
57-
expressionTemp := ch.Factory().NewTempVariable()
58-
ch.EmitContext().AddVariableDeclaration(expressionTemp)
59-
assignment := ch.Factory().NewAssignmentExpression(expressionTemp, left.Expression())
60-
assignment.Loc = left.Expression().Loc
61-
target = ch.Factory().NewPropertyAccessExpression(assignment, nil, left.Name(), ast.NodeFlagsNone)
65+
target = ch.Factory().NewPropertyAccessExpression(objExpr, nil, left.Name(), ast.NodeFlagsNone)
6266
target.Loc = left.Loc
6367

6468
value = ch.Factory().NewPropertyAccessExpression(expressionTemp, nil, left.Name(), ast.NodeFlagsNone)

‎tsc/internal/transformers/estransforms/logicalassignment.go‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ func (ch *logicalAssignmentTransformer) visitBinaryExpression(node *ast.BinaryEx
3434
return ch.Visitor().VisitEachChild(node.AsNode())
3535
}
3636

37-
left := ast.SkipParentheses(ch.Visitor().VisitNode(node.Left))
37+
left := ast.SkipOuterExpressions(ch.Visitor().VisitNode(node.Left), ast.OEKParentheses|ast.OEKPartiallyEmittedExpressions)
3838
assignmentTarget := left
3939
right := ast.SkipParentheses(ch.Visitor().VisitNode(node.Right))
4040

Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
//// [tests/cases/compiler/compoundAssignmentWithTypeOnlyExpressions.ts] ////
2+
3+
//// [compoundAssignmentWithTypeOnlyExpressions.ts]
4+
declare function getObject(): { x: number; [key: number]: number };
5+
let key = 0;
6+
7+
function logicalOrAssignment() {
8+
getObject()[++key]! ||= 1;
9+
(getObject()[++key] as number) ||= 1;
10+
(getObject()[++key] satisfies number) ||= 1;
11+
(<number>getObject()[++key]) ||= 1;
12+
((getObject()[++key]) as number)! ||= 1;
13+
(getObject()[++key]) ||= 1;
14+
15+
getObject().x! ||= 1;
16+
(getObject().x as number) ||= 1;
17+
(getObject().x satisfies number) ||= 1;
18+
(<number>getObject().x) ||= 1;
19+
((getObject().x) as number)! ||= 1;
20+
(getObject().x) ||= 1;
21+
}
22+
23+
function logicalAndAssignment() {
24+
getObject()[++key]! &&= 1;
25+
(getObject()[++key] as number) &&= 1;
26+
(getObject()[++key] satisfies number) &&= 1;
27+
(<number>getObject()[++key]) &&= 1;
28+
((getObject()[++key]) as number)! &&= 1;
29+
(getObject()[++key]) &&= 1;
30+
31+
getObject().x! &&= 1;
32+
(getObject().x as number) &&= 1;
33+
(getObject().x satisfies number) &&= 1;
34+
(<number>getObject().x) &&= 1;
35+
((getObject().x) as number)! &&= 1;
36+
(getObject().x) &&= 1;
37+
}
38+
39+
function nullishAssignment() {
40+
getObject()[++key]! ??= 1;
41+
(getObject()[++key] as number) ??= 1;
42+
(getObject()[++key] satisfies number) ??= 1;
43+
(<number>getObject()[++key]) ??= 1;
44+
((getObject()[++key]) as number)! ??= 1;
45+
(getObject()[++key]) ??= 1;
46+
47+
getObject().x! ??= 1;
48+
(getObject().x as number) ??= 1;
49+
(getObject().x satisfies number) ??= 1;
50+
(<number>getObject().x) ??= 1;
51+
((getObject().x) as number)! ??= 1;
52+
(getObject().x) ??= 1;
53+
}
54+
55+
function exponentiationAssignment() {
56+
getObject()[++key]! **= 2;
57+
(getObject()[++key] as number) **= 2;
58+
(getObject()[++key] satisfies number) **= 2;
59+
(<number>getObject()[++key]) **= 2;
60+
((getObject()[++key]) as number)! **= 2;
61+
(getObject()[++key]) **= 2;
62+
63+
getObject().x! **= 2;
64+
(getObject().x as number) **= 2;
65+
(getObject().x satisfies number) **= 2;
66+
(<number>getObject().x) **= 2;
67+
((getObject().x) as number)! **= 2;
68+
(getObject().x) **= 2;
69+
}
70+
71+
declare function getKey(): "x";
72+
73+
class Base {
74+
get x() { return 2; }
75+
set x(value: number) {}
76+
}
77+
78+
class Derived extends Base {
79+
logicalAssignment() {
80+
super.x! ||= 1;
81+
(super.x as number) &&= 1;
82+
(super.x satisfies number) ??= 1;
83+
(<number>super[getKey()]) ||= 1;
84+
super[getKey()]! &&= 1;
85+
(super[getKey()] as number) ??= 1;
86+
}
87+
88+
exponentiationAssignment() {
89+
super.x! **= 2;
90+
(super.x as number) **= 2;
91+
(super.x satisfies number) **= 2;
92+
(<number>super.x) **= 2;
93+
((super.x) as number)! **= 2;
94+
(super.x) **= 2;
95+
96+
super[getKey()]! **= 2;
97+
(super[getKey()] as number) **= 2;
98+
(super[getKey()] satisfies number) **= 2;
99+
(<number>super[getKey()]) **= 2;
100+
((super[getKey()]) as number)! **= 2;
101+
(super[getKey()]) **= 2;
102+
}
103+
}
104+
105+
106+
//// [compoundAssignmentWithTypeOnlyExpressions.js]
107+
"use strict";
108+
let key = 0;
109+
function logicalOrAssignment() {
110+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t;
111+
(_a = getObject())[_b = ++key] || (_a[_b] = 1);
112+
(_c = getObject())[_d = ++key] || (_c[_d] = 1);
113+
(_e = getObject())[_f = ++key] || (_e[_f] = 1);
114+
(_g = getObject())[_h = ++key] || (_g[_h] = 1);
115+
(_j = getObject())[_k = ++key] || (_j[_k] = 1);
116+
(_l = getObject())[_m = ++key] || (_l[_m] = 1);
117+
(_o = getObject()).x || (_o.x = 1);
118+
(_p = getObject()).x || (_p.x = 1);
119+
(_q = getObject()).x || (_q.x = 1);
120+
(_r = getObject()).x || (_r.x = 1);
121+
(_s = getObject()).x || (_s.x = 1);
122+
(_t = getObject()).x || (_t.x = 1);
123+
}
124+
function logicalAndAssignment() {
125+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t;
126+
(_a = getObject())[_b = ++key] && (_a[_b] = 1);
127+
(_c = getObject())[_d = ++key] && (_c[_d] = 1);
128+
(_e = getObject())[_f = ++key] && (_e[_f] = 1);
129+
(_g = getObject())[_h = ++key] && (_g[_h] = 1);
130+
(_j = getObject())[_k = ++key] && (_j[_k] = 1);
131+
(_l = getObject())[_m = ++key] && (_l[_m] = 1);
132+
(_o = getObject()).x && (_o.x = 1);
133+
(_p = getObject()).x && (_p.x = 1);
134+
(_q = getObject()).x && (_q.x = 1);
135+
(_r = getObject()).x && (_r.x = 1);
136+
(_s = getObject()).x && (_s.x = 1);
137+
(_t = getObject()).x && (_t.x = 1);
138+
}
139+
function nullishAssignment() {
140+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
141+
var _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5;
142+
(_a = (_o = getObject())[_p = ++key]) !== null && _a !== void 0 ? _a : (_o[_p] = 1);
143+
(_b = (_q = getObject())[_r = ++key]) !== null && _b !== void 0 ? _b : (_q[_r] = 1);
144+
(_c = (_s = getObject())[_t = ++key]) !== null && _c !== void 0 ? _c : (_s[_t] = 1);
145+
(_d = (_u = getObject())[_v = ++key]) !== null && _d !== void 0 ? _d : (_u[_v] = 1);
146+
(_e = (_w = getObject())[_x = ++key]) !== null && _e !== void 0 ? _e : (_w[_x] = 1);
147+
(_f = (_y = getObject())[_z = ++key]) !== null && _f !== void 0 ? _f : (_y[_z] = 1);
148+
(_g = (_0 = getObject()).x) !== null && _g !== void 0 ? _g : (_0.x = 1);
149+
(_h = (_1 = getObject()).x) !== null && _h !== void 0 ? _h : (_1.x = 1);
150+
(_j = (_2 = getObject()).x) !== null && _j !== void 0 ? _j : (_2.x = 1);
151+
(_k = (_3 = getObject()).x) !== null && _k !== void 0 ? _k : (_3.x = 1);
152+
(_l = (_4 = getObject()).x) !== null && _l !== void 0 ? _l : (_4.x = 1);
153+
(_m = (_5 = getObject()).x) !== null && _m !== void 0 ? _m : (_5.x = 1);
154+
}
155+
function exponentiationAssignment() {
156+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t;
157+
(_a = getObject())[_b = ++key] = Math.pow(_a[_b], 2);
158+
(_c = getObject())[_d = ++key] = Math.pow(_c[_d], 2);
159+
(_e = getObject())[_f = ++key] = Math.pow(_e[_f], 2);
160+
(_g = getObject())[_h = ++key] = Math.pow(_g[_h], 2);
161+
(_j = getObject())[_k = ++key] = Math.pow(_j[_k], 2);
162+
(_l = getObject())[_m = ++key] = Math.pow(_l[_m], 2);
163+
(_o = getObject()).x = Math.pow(_o.x, 2);
164+
(_p = getObject()).x = Math.pow(_p.x, 2);
165+
(_q = getObject()).x = Math.pow(_q.x, 2);
166+
(_r = getObject()).x = Math.pow(_r.x, 2);
167+
(_s = getObject()).x = Math.pow(_s.x, 2);
168+
(_t = getObject()).x = Math.pow(_t.x, 2);
169+
}
170+
class Base {
171+
get x() { return 2; }
172+
set x(value) { }
173+
}
174+
class Derived extends Base {
175+
logicalAssignment() {
176+
var _a, _b;
177+
var _c, _d, _e;
178+
super.x || (super.x = 1);
179+
super.x && (super.x = 1);
180+
(_a = super.x) !== null && _a !== void 0 ? _a : (super.x = 1);
181+
super[_c = getKey()] || (super[_c] = 1);
182+
super[_d = getKey()] && (super[_d] = 1);
183+
(_b = super[_e = getKey()]) !== null && _b !== void 0 ? _b : (super[_e] = 1);
184+
}
185+
exponentiationAssignment() {
186+
var _a, _b, _c, _d, _e, _f;
187+
super.x = Math.pow(super.x, 2);
188+
super.x = Math.pow(super.x, 2);
189+
super.x = Math.pow(super.x, 2);
190+
super.x = Math.pow(super.x, 2);
191+
super.x = Math.pow(super.x, 2);
192+
super.x = Math.pow(super.x, 2);
193+
super[_a = getKey()] = Math.pow(super[_a], 2);
194+
super[_b = getKey()] = Math.pow(super[_b], 2);
195+
super[_c = getKey()] = Math.pow(super[_c], 2);
196+
super[_d = getKey()] = Math.pow(super[_d], 2);
197+
super[_e = getKey()] = Math.pow(super[_e], 2);
198+
super[_f = getKey()] = Math.pow(super[_f], 2);
199+
}
200+
}

0 commit comments

Comments
 (0)