Skip to content

Commit 6b4d0bf

Browse files
authored
Avoid effect of element access expression (#39174)
* Avoid effect of element access expression * Avoid unnecessary copy * Add more tests
1 parent d610bbd commit 6b4d0bf

16 files changed

+377
-45
lines changed

src/compiler/transformers/esnext.ts

+23-14
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ namespace ts {
2525
if (isLogicalOrCoalescingAssignmentExpression(binaryExpression)) {
2626
return transformLogicalAssignment(binaryExpression);
2727
}
28-
// falls through
28+
// falls through
2929
default:
3030
return visitEachChild(node, visitor, context);
3131
}
@@ -37,32 +37,41 @@ namespace ts {
3737
let left = skipParentheses(visitNode(binaryExpression.left, visitor, isLeftHandSideExpression));
3838
let assignmentTarget = left;
3939
const right = skipParentheses(visitNode(binaryExpression.right, visitor, isExpression));
40+
4041
if (isAccessExpression(left)) {
41-
const tempVariable = factory.createTempVariable(hoistVariableDeclaration);
42+
const propertyAccessTargetSimpleCopiable = isSimpleCopiableExpression(left.expression);
43+
const propertyAccessTarget = propertyAccessTargetSimpleCopiable ? left.expression :
44+
factory.createTempVariable(hoistVariableDeclaration);
45+
const propertyAccessTargetAssignment = propertyAccessTargetSimpleCopiable ? left.expression : factory.createAssignment(
46+
propertyAccessTarget,
47+
left.expression
48+
);
49+
4250
if (isPropertyAccessExpression(left)) {
4351
assignmentTarget = factory.createPropertyAccessExpression(
44-
tempVariable,
52+
propertyAccessTarget,
4553
left.name
4654
);
4755
left = factory.createPropertyAccessExpression(
48-
factory.createAssignment(
49-
tempVariable,
50-
left.expression
51-
),
56+
propertyAccessTargetAssignment,
5257
left.name
5358
);
5459
}
5560
else {
61+
const elementAccessArgumentSimpleCopiable = isSimpleCopiableExpression(left.argumentExpression);
62+
const elementAccessArgument = elementAccessArgumentSimpleCopiable ? left.argumentExpression :
63+
factory.createTempVariable(hoistVariableDeclaration);
64+
5665
assignmentTarget = factory.createElementAccessExpression(
57-
tempVariable,
58-
left.argumentExpression
66+
propertyAccessTarget,
67+
elementAccessArgument
5968
);
6069
left = factory.createElementAccessExpression(
61-
factory.createAssignment(
62-
tempVariable,
63-
left.expression
64-
),
65-
left.argumentExpression
70+
propertyAccessTargetAssignment,
71+
elementAccessArgumentSimpleCopiable ? left.argumentExpression : factory.createAssignment(
72+
elementAccessArgument,
73+
left.argumentExpression
74+
)
6675
);
6776
}
6877
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
//// [logicalAssignment10.ts]
2+
var count = 0;
3+
var obj = {};
4+
function incr() {
5+
return ++count;
6+
}
7+
8+
const oobj = {
9+
obj
10+
}
11+
12+
obj[incr()] ??= incr();
13+
oobj["obj"][incr()] ??= incr();
14+
15+
16+
//// [logicalAssignment10.js]
17+
var _a, _b;
18+
var _c, _d, _e;
19+
var count = 0;
20+
var obj = {};
21+
function incr() {
22+
return ++count;
23+
}
24+
const oobj = {
25+
obj
26+
};
27+
(_a = obj[_c = incr()]) !== null && _a !== void 0 ? _a : (obj[_c] = incr());
28+
(_b = (_d = oobj["obj"])[_e = incr()]) !== null && _b !== void 0 ? _b : (_d[_e] = incr());
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
=== tests/cases/conformance/esnext/logicalAssignment/logicalAssignment10.ts ===
2+
var count = 0;
3+
>count : Symbol(count, Decl(logicalAssignment10.ts, 0, 3))
4+
5+
var obj = {};
6+
>obj : Symbol(obj, Decl(logicalAssignment10.ts, 1, 3))
7+
8+
function incr() {
9+
>incr : Symbol(incr, Decl(logicalAssignment10.ts, 1, 13))
10+
11+
return ++count;
12+
>count : Symbol(count, Decl(logicalAssignment10.ts, 0, 3))
13+
}
14+
15+
const oobj = {
16+
>oobj : Symbol(oobj, Decl(logicalAssignment10.ts, 6, 5))
17+
18+
obj
19+
>obj : Symbol(obj, Decl(logicalAssignment10.ts, 6, 14))
20+
}
21+
22+
obj[incr()] ??= incr();
23+
>obj : Symbol(obj, Decl(logicalAssignment10.ts, 1, 3))
24+
>incr : Symbol(incr, Decl(logicalAssignment10.ts, 1, 13))
25+
>incr : Symbol(incr, Decl(logicalAssignment10.ts, 1, 13))
26+
27+
oobj["obj"][incr()] ??= incr();
28+
>oobj : Symbol(oobj, Decl(logicalAssignment10.ts, 6, 5))
29+
>"obj" : Symbol(obj, Decl(logicalAssignment10.ts, 6, 14))
30+
>incr : Symbol(incr, Decl(logicalAssignment10.ts, 1, 13))
31+
>incr : Symbol(incr, Decl(logicalAssignment10.ts, 1, 13))
32+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
=== tests/cases/conformance/esnext/logicalAssignment/logicalAssignment10.ts ===
2+
var count = 0;
3+
>count : number
4+
>0 : 0
5+
6+
var obj = {};
7+
>obj : {}
8+
>{} : {}
9+
10+
function incr() {
11+
>incr : () => number
12+
13+
return ++count;
14+
>++count : number
15+
>count : number
16+
}
17+
18+
const oobj = {
19+
>oobj : { obj: {}; }
20+
>{ obj} : { obj: {}; }
21+
22+
obj
23+
>obj : {}
24+
}
25+
26+
obj[incr()] ??= incr();
27+
>obj[incr()] ??= incr() : any
28+
>obj[incr()] : error
29+
>obj : {}
30+
>incr() : number
31+
>incr : () => number
32+
>incr() : number
33+
>incr : () => number
34+
35+
oobj["obj"][incr()] ??= incr();
36+
>oobj["obj"][incr()] ??= incr() : any
37+
>oobj["obj"][incr()] : error
38+
>oobj["obj"] : {}
39+
>oobj : { obj: {}; }
40+
>"obj" : "obj"
41+
>incr() : number
42+
>incr : () => number
43+
>incr() : number
44+
>incr : () => number
45+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//// [logicalAssignment10.ts]
2+
var count = 0;
3+
var obj = {};
4+
function incr() {
5+
return ++count;
6+
}
7+
8+
const oobj = {
9+
obj
10+
}
11+
12+
obj[incr()] ??= incr();
13+
oobj["obj"][incr()] ??= incr();
14+
15+
16+
//// [logicalAssignment10.js]
17+
var _a, _b, _c;
18+
var count = 0;
19+
var obj = {};
20+
function incr() {
21+
return ++count;
22+
}
23+
const oobj = {
24+
obj
25+
};
26+
obj[_a = incr()] ?? (obj[_a] = incr());
27+
(_b = oobj["obj"])[_c = incr()] ?? (_b[_c] = incr());
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
=== tests/cases/conformance/esnext/logicalAssignment/logicalAssignment10.ts ===
2+
var count = 0;
3+
>count : Symbol(count, Decl(logicalAssignment10.ts, 0, 3))
4+
5+
var obj = {};
6+
>obj : Symbol(obj, Decl(logicalAssignment10.ts, 1, 3))
7+
8+
function incr() {
9+
>incr : Symbol(incr, Decl(logicalAssignment10.ts, 1, 13))
10+
11+
return ++count;
12+
>count : Symbol(count, Decl(logicalAssignment10.ts, 0, 3))
13+
}
14+
15+
const oobj = {
16+
>oobj : Symbol(oobj, Decl(logicalAssignment10.ts, 6, 5))
17+
18+
obj
19+
>obj : Symbol(obj, Decl(logicalAssignment10.ts, 6, 14))
20+
}
21+
22+
obj[incr()] ??= incr();
23+
>obj : Symbol(obj, Decl(logicalAssignment10.ts, 1, 3))
24+
>incr : Symbol(incr, Decl(logicalAssignment10.ts, 1, 13))
25+
>incr : Symbol(incr, Decl(logicalAssignment10.ts, 1, 13))
26+
27+
oobj["obj"][incr()] ??= incr();
28+
>oobj : Symbol(oobj, Decl(logicalAssignment10.ts, 6, 5))
29+
>"obj" : Symbol(obj, Decl(logicalAssignment10.ts, 6, 14))
30+
>incr : Symbol(incr, Decl(logicalAssignment10.ts, 1, 13))
31+
>incr : Symbol(incr, Decl(logicalAssignment10.ts, 1, 13))
32+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
=== tests/cases/conformance/esnext/logicalAssignment/logicalAssignment10.ts ===
2+
var count = 0;
3+
>count : number
4+
>0 : 0
5+
6+
var obj = {};
7+
>obj : {}
8+
>{} : {}
9+
10+
function incr() {
11+
>incr : () => number
12+
13+
return ++count;
14+
>++count : number
15+
>count : number
16+
}
17+
18+
const oobj = {
19+
>oobj : { obj: {}; }
20+
>{ obj} : { obj: {}; }
21+
22+
obj
23+
>obj : {}
24+
}
25+
26+
obj[incr()] ??= incr();
27+
>obj[incr()] ??= incr() : any
28+
>obj[incr()] : error
29+
>obj : {}
30+
>incr() : number
31+
>incr : () => number
32+
>incr() : number
33+
>incr : () => number
34+
35+
oobj["obj"][incr()] ??= incr();
36+
>oobj["obj"][incr()] ??= incr() : any
37+
>oobj["obj"][incr()] : error
38+
>oobj["obj"] : {}
39+
>oobj : { obj: {}; }
40+
>"obj" : "obj"
41+
>incr() : number
42+
>incr : () => number
43+
>incr() : number
44+
>incr : () => number
45+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//// [logicalAssignment10.ts]
2+
var count = 0;
3+
var obj = {};
4+
function incr() {
5+
return ++count;
6+
}
7+
8+
const oobj = {
9+
obj
10+
}
11+
12+
obj[incr()] ??= incr();
13+
oobj["obj"][incr()] ??= incr();
14+
15+
16+
//// [logicalAssignment10.js]
17+
var count = 0;
18+
var obj = {};
19+
function incr() {
20+
return ++count;
21+
}
22+
const oobj = {
23+
obj
24+
};
25+
obj[incr()] ??= incr();
26+
oobj["obj"][incr()] ??= incr();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
=== tests/cases/conformance/esnext/logicalAssignment/logicalAssignment10.ts ===
2+
var count = 0;
3+
>count : Symbol(count, Decl(logicalAssignment10.ts, 0, 3))
4+
5+
var obj = {};
6+
>obj : Symbol(obj, Decl(logicalAssignment10.ts, 1, 3))
7+
8+
function incr() {
9+
>incr : Symbol(incr, Decl(logicalAssignment10.ts, 1, 13))
10+
11+
return ++count;
12+
>count : Symbol(count, Decl(logicalAssignment10.ts, 0, 3))
13+
}
14+
15+
const oobj = {
16+
>oobj : Symbol(oobj, Decl(logicalAssignment10.ts, 6, 5))
17+
18+
obj
19+
>obj : Symbol(obj, Decl(logicalAssignment10.ts, 6, 14))
20+
}
21+
22+
obj[incr()] ??= incr();
23+
>obj : Symbol(obj, Decl(logicalAssignment10.ts, 1, 3))
24+
>incr : Symbol(incr, Decl(logicalAssignment10.ts, 1, 13))
25+
>incr : Symbol(incr, Decl(logicalAssignment10.ts, 1, 13))
26+
27+
oobj["obj"][incr()] ??= incr();
28+
>oobj : Symbol(oobj, Decl(logicalAssignment10.ts, 6, 5))
29+
>"obj" : Symbol(obj, Decl(logicalAssignment10.ts, 6, 14))
30+
>incr : Symbol(incr, Decl(logicalAssignment10.ts, 1, 13))
31+
>incr : Symbol(incr, Decl(logicalAssignment10.ts, 1, 13))
32+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
=== tests/cases/conformance/esnext/logicalAssignment/logicalAssignment10.ts ===
2+
var count = 0;
3+
>count : number
4+
>0 : 0
5+
6+
var obj = {};
7+
>obj : {}
8+
>{} : {}
9+
10+
function incr() {
11+
>incr : () => number
12+
13+
return ++count;
14+
>++count : number
15+
>count : number
16+
}
17+
18+
const oobj = {
19+
>oobj : { obj: {}; }
20+
>{ obj} : { obj: {}; }
21+
22+
obj
23+
>obj : {}
24+
}
25+
26+
obj[incr()] ??= incr();
27+
>obj[incr()] ??= incr() : any
28+
>obj[incr()] : error
29+
>obj : {}
30+
>incr() : number
31+
>incr : () => number
32+
>incr() : number
33+
>incr : () => number
34+
35+
oobj["obj"][incr()] ??= incr();
36+
>oobj["obj"][incr()] ??= incr() : any
37+
>oobj["obj"][incr()] : error
38+
>oobj["obj"] : {}
39+
>oobj : { obj: {}; }
40+
>"obj" : "obj"
41+
>incr() : number
42+
>incr : () => number
43+
>incr() : number
44+
>incr : () => number
45+

0 commit comments

Comments
 (0)