Avoid effect of element access expression (#39174)

* Avoid effect of element access expression

* Avoid unnecessary copy

* Add more tests
This commit is contained in:
Wenlu Wang 2020-06-26 08:38:05 +08:00 committed by GitHub
parent d610bbdaef
commit 6b4d0bff40
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 377 additions and 45 deletions

View file

@ -25,7 +25,7 @@ namespace ts {
if (isLogicalOrCoalescingAssignmentExpression(binaryExpression)) {
return transformLogicalAssignment(binaryExpression);
}
// falls through
// falls through
default:
return visitEachChild(node, visitor, context);
}
@ -37,32 +37,41 @@ namespace ts {
let left = skipParentheses(visitNode(binaryExpression.left, visitor, isLeftHandSideExpression));
let assignmentTarget = left;
const right = skipParentheses(visitNode(binaryExpression.right, visitor, isExpression));
if (isAccessExpression(left)) {
const tempVariable = factory.createTempVariable(hoistVariableDeclaration);
const propertyAccessTargetSimpleCopiable = isSimpleCopiableExpression(left.expression);
const propertyAccessTarget = propertyAccessTargetSimpleCopiable ? left.expression :
factory.createTempVariable(hoistVariableDeclaration);
const propertyAccessTargetAssignment = propertyAccessTargetSimpleCopiable ? left.expression : factory.createAssignment(
propertyAccessTarget,
left.expression
);
if (isPropertyAccessExpression(left)) {
assignmentTarget = factory.createPropertyAccessExpression(
tempVariable,
propertyAccessTarget,
left.name
);
left = factory.createPropertyAccessExpression(
factory.createAssignment(
tempVariable,
left.expression
),
propertyAccessTargetAssignment,
left.name
);
}
else {
const elementAccessArgumentSimpleCopiable = isSimpleCopiableExpression(left.argumentExpression);
const elementAccessArgument = elementAccessArgumentSimpleCopiable ? left.argumentExpression :
factory.createTempVariable(hoistVariableDeclaration);
assignmentTarget = factory.createElementAccessExpression(
tempVariable,
left.argumentExpression
propertyAccessTarget,
elementAccessArgument
);
left = factory.createElementAccessExpression(
factory.createAssignment(
tempVariable,
left.expression
),
left.argumentExpression
propertyAccessTargetAssignment,
elementAccessArgumentSimpleCopiable ? left.argumentExpression : factory.createAssignment(
elementAccessArgument,
left.argumentExpression
)
);
}
}

View file

@ -0,0 +1,28 @@
//// [logicalAssignment10.ts]
var count = 0;
var obj = {};
function incr() {
return ++count;
}
const oobj = {
obj
}
obj[incr()] ??= incr();
oobj["obj"][incr()] ??= incr();
//// [logicalAssignment10.js]
var _a, _b;
var _c, _d, _e;
var count = 0;
var obj = {};
function incr() {
return ++count;
}
const oobj = {
obj
};
(_a = obj[_c = incr()]) !== null && _a !== void 0 ? _a : (obj[_c] = incr());
(_b = (_d = oobj["obj"])[_e = incr()]) !== null && _b !== void 0 ? _b : (_d[_e] = incr());

View file

@ -0,0 +1,32 @@
=== tests/cases/conformance/esnext/logicalAssignment/logicalAssignment10.ts ===
var count = 0;
>count : Symbol(count, Decl(logicalAssignment10.ts, 0, 3))
var obj = {};
>obj : Symbol(obj, Decl(logicalAssignment10.ts, 1, 3))
function incr() {
>incr : Symbol(incr, Decl(logicalAssignment10.ts, 1, 13))
return ++count;
>count : Symbol(count, Decl(logicalAssignment10.ts, 0, 3))
}
const oobj = {
>oobj : Symbol(oobj, Decl(logicalAssignment10.ts, 6, 5))
obj
>obj : Symbol(obj, Decl(logicalAssignment10.ts, 6, 14))
}
obj[incr()] ??= incr();
>obj : Symbol(obj, Decl(logicalAssignment10.ts, 1, 3))
>incr : Symbol(incr, Decl(logicalAssignment10.ts, 1, 13))
>incr : Symbol(incr, Decl(logicalAssignment10.ts, 1, 13))
oobj["obj"][incr()] ??= incr();
>oobj : Symbol(oobj, Decl(logicalAssignment10.ts, 6, 5))
>"obj" : Symbol(obj, Decl(logicalAssignment10.ts, 6, 14))
>incr : Symbol(incr, Decl(logicalAssignment10.ts, 1, 13))
>incr : Symbol(incr, Decl(logicalAssignment10.ts, 1, 13))

View file

@ -0,0 +1,45 @@
=== tests/cases/conformance/esnext/logicalAssignment/logicalAssignment10.ts ===
var count = 0;
>count : number
>0 : 0
var obj = {};
>obj : {}
>{} : {}
function incr() {
>incr : () => number
return ++count;
>++count : number
>count : number
}
const oobj = {
>oobj : { obj: {}; }
>{ obj} : { obj: {}; }
obj
>obj : {}
}
obj[incr()] ??= incr();
>obj[incr()] ??= incr() : any
>obj[incr()] : error
>obj : {}
>incr() : number
>incr : () => number
>incr() : number
>incr : () => number
oobj["obj"][incr()] ??= incr();
>oobj["obj"][incr()] ??= incr() : any
>oobj["obj"][incr()] : error
>oobj["obj"] : {}
>oobj : { obj: {}; }
>"obj" : "obj"
>incr() : number
>incr : () => number
>incr() : number
>incr : () => number

View file

@ -0,0 +1,27 @@
//// [logicalAssignment10.ts]
var count = 0;
var obj = {};
function incr() {
return ++count;
}
const oobj = {
obj
}
obj[incr()] ??= incr();
oobj["obj"][incr()] ??= incr();
//// [logicalAssignment10.js]
var _a, _b, _c;
var count = 0;
var obj = {};
function incr() {
return ++count;
}
const oobj = {
obj
};
obj[_a = incr()] ?? (obj[_a] = incr());
(_b = oobj["obj"])[_c = incr()] ?? (_b[_c] = incr());

View file

@ -0,0 +1,32 @@
=== tests/cases/conformance/esnext/logicalAssignment/logicalAssignment10.ts ===
var count = 0;
>count : Symbol(count, Decl(logicalAssignment10.ts, 0, 3))
var obj = {};
>obj : Symbol(obj, Decl(logicalAssignment10.ts, 1, 3))
function incr() {
>incr : Symbol(incr, Decl(logicalAssignment10.ts, 1, 13))
return ++count;
>count : Symbol(count, Decl(logicalAssignment10.ts, 0, 3))
}
const oobj = {
>oobj : Symbol(oobj, Decl(logicalAssignment10.ts, 6, 5))
obj
>obj : Symbol(obj, Decl(logicalAssignment10.ts, 6, 14))
}
obj[incr()] ??= incr();
>obj : Symbol(obj, Decl(logicalAssignment10.ts, 1, 3))
>incr : Symbol(incr, Decl(logicalAssignment10.ts, 1, 13))
>incr : Symbol(incr, Decl(logicalAssignment10.ts, 1, 13))
oobj["obj"][incr()] ??= incr();
>oobj : Symbol(oobj, Decl(logicalAssignment10.ts, 6, 5))
>"obj" : Symbol(obj, Decl(logicalAssignment10.ts, 6, 14))
>incr : Symbol(incr, Decl(logicalAssignment10.ts, 1, 13))
>incr : Symbol(incr, Decl(logicalAssignment10.ts, 1, 13))

View file

@ -0,0 +1,45 @@
=== tests/cases/conformance/esnext/logicalAssignment/logicalAssignment10.ts ===
var count = 0;
>count : number
>0 : 0
var obj = {};
>obj : {}
>{} : {}
function incr() {
>incr : () => number
return ++count;
>++count : number
>count : number
}
const oobj = {
>oobj : { obj: {}; }
>{ obj} : { obj: {}; }
obj
>obj : {}
}
obj[incr()] ??= incr();
>obj[incr()] ??= incr() : any
>obj[incr()] : error
>obj : {}
>incr() : number
>incr : () => number
>incr() : number
>incr : () => number
oobj["obj"][incr()] ??= incr();
>oobj["obj"][incr()] ??= incr() : any
>oobj["obj"][incr()] : error
>oobj["obj"] : {}
>oobj : { obj: {}; }
>"obj" : "obj"
>incr() : number
>incr : () => number
>incr() : number
>incr : () => number

View file

@ -0,0 +1,26 @@
//// [logicalAssignment10.ts]
var count = 0;
var obj = {};
function incr() {
return ++count;
}
const oobj = {
obj
}
obj[incr()] ??= incr();
oobj["obj"][incr()] ??= incr();
//// [logicalAssignment10.js]
var count = 0;
var obj = {};
function incr() {
return ++count;
}
const oobj = {
obj
};
obj[incr()] ??= incr();
oobj["obj"][incr()] ??= incr();

View file

@ -0,0 +1,32 @@
=== tests/cases/conformance/esnext/logicalAssignment/logicalAssignment10.ts ===
var count = 0;
>count : Symbol(count, Decl(logicalAssignment10.ts, 0, 3))
var obj = {};
>obj : Symbol(obj, Decl(logicalAssignment10.ts, 1, 3))
function incr() {
>incr : Symbol(incr, Decl(logicalAssignment10.ts, 1, 13))
return ++count;
>count : Symbol(count, Decl(logicalAssignment10.ts, 0, 3))
}
const oobj = {
>oobj : Symbol(oobj, Decl(logicalAssignment10.ts, 6, 5))
obj
>obj : Symbol(obj, Decl(logicalAssignment10.ts, 6, 14))
}
obj[incr()] ??= incr();
>obj : Symbol(obj, Decl(logicalAssignment10.ts, 1, 3))
>incr : Symbol(incr, Decl(logicalAssignment10.ts, 1, 13))
>incr : Symbol(incr, Decl(logicalAssignment10.ts, 1, 13))
oobj["obj"][incr()] ??= incr();
>oobj : Symbol(oobj, Decl(logicalAssignment10.ts, 6, 5))
>"obj" : Symbol(obj, Decl(logicalAssignment10.ts, 6, 14))
>incr : Symbol(incr, Decl(logicalAssignment10.ts, 1, 13))
>incr : Symbol(incr, Decl(logicalAssignment10.ts, 1, 13))

View file

@ -0,0 +1,45 @@
=== tests/cases/conformance/esnext/logicalAssignment/logicalAssignment10.ts ===
var count = 0;
>count : number
>0 : 0
var obj = {};
>obj : {}
>{} : {}
function incr() {
>incr : () => number
return ++count;
>++count : number
>count : number
}
const oobj = {
>oobj : { obj: {}; }
>{ obj} : { obj: {}; }
obj
>obj : {}
}
obj[incr()] ??= incr();
>obj[incr()] ??= incr() : any
>obj[incr()] : error
>obj : {}
>incr() : number
>incr : () => number
>incr() : number
>incr : () => number
oobj["obj"][incr()] ??= incr();
>oobj["obj"][incr()] ??= incr() : any
>oobj["obj"][incr()] : error
>oobj["obj"] : {}
>oobj : { obj: {}; }
>"obj" : "obj"
>incr() : number
>incr : () => number
>incr() : number
>incr : () => number

View file

@ -31,13 +31,13 @@ c.foo.bar().baz ??= result.foo.bar().baz
//// [logicalAssignment2.js]
"use strict";
var _a, _b, _c;
var _d, _e, _f, _g, _h, _j, _k, _l, _m;
(_d = a).baz && (_d.baz = result.baz);
(_e = b).baz || (_e.baz = result.baz);
(_a = (_f = c).baz) !== null && _a !== void 0 ? _a : (_f.baz = result.baz);
(_g = a.foo)["baz"] && (_g["baz"] = result.foo.baz);
(_h = b.foo)["baz"] || (_h["baz"] = result.foo.baz);
(_b = (_j = c.foo)["baz"]) !== null && _b !== void 0 ? _b : (_j["baz"] = result.foo.baz);
(_k = a.foo.bar()).baz && (_k.baz = result.foo.bar().baz);
(_l = b.foo.bar()).baz || (_l.baz = result.foo.bar().baz);
(_c = (_m = c.foo.bar()).baz) !== null && _c !== void 0 ? _c : (_m.baz = result.foo.bar().baz);
var _d, _e, _f, _g, _h, _j;
a.baz && (a.baz = result.baz);
b.baz || (b.baz = result.baz);
(_a = c.baz) !== null && _a !== void 0 ? _a : (c.baz = result.baz);
(_d = a.foo)["baz"] && (_d["baz"] = result.foo.baz);
(_e = b.foo)["baz"] || (_e["baz"] = result.foo.baz);
(_b = (_f = c.foo)["baz"]) !== null && _b !== void 0 ? _b : (_f["baz"] = result.foo.baz);
(_g = a.foo.bar()).baz && (_g.baz = result.foo.bar().baz);
(_h = b.foo.bar()).baz || (_h.baz = result.foo.bar().baz);
(_c = (_j = c.foo.bar()).baz) !== null && _c !== void 0 ? _c : (_j.baz = result.foo.bar().baz);

View file

@ -30,13 +30,13 @@ c.foo.bar().baz ??= result.foo.bar().baz
//// [logicalAssignment2.js]
"use strict";
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
(_a = a).baz && (_a.baz = result.baz);
(_b = b).baz || (_b.baz = result.baz);
(_c = c).baz ?? (_c.baz = result.baz);
(_d = a.foo)["baz"] && (_d["baz"] = result.foo.baz);
(_e = b.foo)["baz"] || (_e["baz"] = result.foo.baz);
(_f = c.foo)["baz"] ?? (_f["baz"] = result.foo.baz);
(_g = a.foo.bar()).baz && (_g.baz = result.foo.bar().baz);
(_h = b.foo.bar()).baz || (_h.baz = result.foo.bar().baz);
(_j = c.foo.bar()).baz ?? (_j.baz = result.foo.bar().baz);
var _a, _b, _c, _d, _e, _f;
a.baz && (a.baz = result.baz);
b.baz || (b.baz = result.baz);
c.baz ?? (c.baz = result.baz);
(_a = a.foo)["baz"] && (_a["baz"] = result.foo.baz);
(_b = b.foo)["baz"] || (_b["baz"] = result.foo.baz);
(_c = c.foo)["baz"] ?? (_c["baz"] = result.foo.baz);
(_d = a.foo.bar()).baz && (_d.baz = result.foo.bar().baz);
(_e = b.foo.bar()).baz || (_e.baz = result.foo.bar().baz);
(_f = c.foo.bar()).baz ?? (_f.baz = result.foo.bar().baz);

View file

@ -17,7 +17,6 @@ declare const c: A;
//// [logicalAssignment3.js]
"use strict";
var _a;
var _b, _c, _d;
(_b = a).baz && (_b.baz = result.baz);
(_c = b).baz || (_c.baz = result.baz);
(_a = (_d = c).baz) !== null && _a !== void 0 ? _a : (_d.baz = result.baz);
a.baz && (a.baz = result.baz);
b.baz || (b.baz = result.baz);
(_a = c.baz) !== null && _a !== void 0 ? _a : (c.baz = result.baz);

View file

@ -16,7 +16,6 @@ declare const c: A;
//// [logicalAssignment3.js]
"use strict";
var _a, _b, _c;
(_a = a).baz && (_a.baz = result.baz);
(_b = b).baz || (_b.baz = result.baz);
(_c = c).baz ?? (_c.baz = result.baz);
a.baz && (a.baz = result.baz);
b.baz || (b.baz = result.baz);
c.baz ?? (c.baz = result.baz);

View file

@ -8,6 +8,5 @@ x.a &&= false;
//// [logicalAssignment9.js]
"use strict";
var _a;
var _b, _c;
(_a = (_b = x).a) !== null && _a !== void 0 ? _a : (_b.a = true);
(_c = x).a && (_c.a = false);
(_a = x.a) !== null && _a !== void 0 ? _a : (x.a = true);
x.a && (x.a = false);

View file

@ -0,0 +1,14 @@
// @target: esnext, es2020, es2015
var count = 0;
var obj = {};
function incr() {
return ++count;
}
const oobj = {
obj
}
obj[incr()] ??= incr();
oobj["obj"][incr()] ??= incr();