diff --git a/src/compiler/transformers/esnext.ts b/src/compiler/transformers/esnext.ts index 6edbb65bf4..df42ff4eb8 100644 --- a/src/compiler/transformers/esnext.ts +++ b/src/compiler/transformers/esnext.ts @@ -1,6 +1,9 @@ /*@internal*/ namespace ts { export function transformESNext(context: TransformationContext) { + const { + hoistVariableDeclaration + } = context; return chainBundle(transformSourceFile); function transformSourceFile(node: SourceFile) { @@ -31,15 +34,45 @@ namespace ts { const operator = binaryExpression.operatorToken; if (isCompoundAssignment(operator.kind) && isLogicalOrCoalescingAssignmentOperator(operator.kind)) { const nonAssignmentOperator = getNonAssignmentOperatorForCompoundAssignment(operator.kind); - const left = visitNode(binaryExpression.left, visitor, isExpression); - const right = visitNode(binaryExpression.right, visitor, isExpression); + let left = skipParentheses(visitNode(binaryExpression.left, visitor, isLeftHandSideExpression)); + let assignmentTarget = left + const right = skipParentheses(visitNode(binaryExpression.right, visitor, isExpression)); + if (isPropertyAccessExpression(left) || isElementAccessExpression(left)) { + const tempVariable = createTempVariable(hoistVariableDeclaration) + if (isPropertyAccessExpression(left)) { + assignmentTarget = createPropertyAccess( + tempVariable, + left.name + ); + left = createPropertyAccess( + createAssignment( + tempVariable, + left.expression + ), + left.name + ); + } + else { + assignmentTarget = createElementAccess( + tempVariable, + left.argumentExpression + ); + left = createElementAccess( + createAssignment( + tempVariable, + left.expression + ), + left.argumentExpression + ); + } + } return createBinary( left, nonAssignmentOperator, createParen( createAssignment( - left, + assignmentTarget, right ) ) diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index efd6c9afd5..6f5180e70a 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -388,28 +388,29 @@ declare namespace ts { JSDocAugmentsTag = 310, JSDocImplementsTag = 311, JSDocAuthorTag = 312, - JSDocClassTag = 313, - JSDocPublicTag = 314, - JSDocPrivateTag = 315, - JSDocProtectedTag = 316, - JSDocReadonlyTag = 317, - JSDocCallbackTag = 318, - JSDocEnumTag = 319, - JSDocParameterTag = 320, - JSDocReturnTag = 321, - JSDocThisTag = 322, - JSDocTypeTag = 323, - JSDocTemplateTag = 324, - JSDocTypedefTag = 325, - JSDocPropertyTag = 326, - SyntaxList = 327, - NotEmittedStatement = 328, - PartiallyEmittedExpression = 329, - CommaListExpression = 330, - MergeDeclarationMarker = 331, - EndOfDeclarationMarker = 332, - SyntheticReferenceExpression = 333, - Count = 334, + JSDocDeprecatedTag = 313, + JSDocClassTag = 314, + JSDocPublicTag = 315, + JSDocPrivateTag = 316, + JSDocProtectedTag = 317, + JSDocReadonlyTag = 318, + JSDocCallbackTag = 319, + JSDocEnumTag = 320, + JSDocParameterTag = 321, + JSDocReturnTag = 322, + JSDocThisTag = 323, + JSDocTypeTag = 324, + JSDocTemplateTag = 325, + JSDocTypedefTag = 326, + JSDocPropertyTag = 327, + SyntaxList = 328, + NotEmittedStatement = 329, + PartiallyEmittedExpression = 330, + CommaListExpression = 331, + MergeDeclarationMarker = 332, + EndOfDeclarationMarker = 333, + SyntheticReferenceExpression = 334, + Count = 335, FirstAssignment = 62, LastAssignment = 77, FirstCompoundAssignment = 63, @@ -438,9 +439,9 @@ declare namespace ts { LastStatement = 244, FirstNode = 156, FirstJSDocNode = 297, - LastJSDocNode = 326, + LastJSDocNode = 327, FirstJSDocTagNode = 309, - LastJSDocTagNode = 326, + LastJSDocTagNode = 327, } export enum NodeFlags { None = 0, diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 1efec605a9..4570f408c1 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -388,28 +388,29 @@ declare namespace ts { JSDocAugmentsTag = 310, JSDocImplementsTag = 311, JSDocAuthorTag = 312, - JSDocClassTag = 313, - JSDocPublicTag = 314, - JSDocPrivateTag = 315, - JSDocProtectedTag = 316, - JSDocReadonlyTag = 317, - JSDocCallbackTag = 318, - JSDocEnumTag = 319, - JSDocParameterTag = 320, - JSDocReturnTag = 321, - JSDocThisTag = 322, - JSDocTypeTag = 323, - JSDocTemplateTag = 324, - JSDocTypedefTag = 325, - JSDocPropertyTag = 326, - SyntaxList = 327, - NotEmittedStatement = 328, - PartiallyEmittedExpression = 329, - CommaListExpression = 330, - MergeDeclarationMarker = 331, - EndOfDeclarationMarker = 332, - SyntheticReferenceExpression = 333, - Count = 334, + JSDocDeprecatedTag = 313, + JSDocClassTag = 314, + JSDocPublicTag = 315, + JSDocPrivateTag = 316, + JSDocProtectedTag = 317, + JSDocReadonlyTag = 318, + JSDocCallbackTag = 319, + JSDocEnumTag = 320, + JSDocParameterTag = 321, + JSDocReturnTag = 322, + JSDocThisTag = 323, + JSDocTypeTag = 324, + JSDocTemplateTag = 325, + JSDocTypedefTag = 326, + JSDocPropertyTag = 327, + SyntaxList = 328, + NotEmittedStatement = 329, + PartiallyEmittedExpression = 330, + CommaListExpression = 331, + MergeDeclarationMarker = 332, + EndOfDeclarationMarker = 333, + SyntheticReferenceExpression = 334, + Count = 335, FirstAssignment = 62, LastAssignment = 77, FirstCompoundAssignment = 63, @@ -438,9 +439,9 @@ declare namespace ts { LastStatement = 244, FirstNode = 156, FirstJSDocNode = 297, - LastJSDocNode = 326, + LastJSDocNode = 327, FirstJSDocTagNode = 309, - LastJSDocTagNode = 326, + LastJSDocTagNode = 327, } export enum NodeFlags { None = 0, diff --git a/tests/baselines/reference/logicalAssignment2(target=es2015).js b/tests/baselines/reference/logicalAssignment2(target=es2015).js index f07da1575f..efeafc045b 100644 --- a/tests/baselines/reference/logicalAssignment2(target=es2015).js +++ b/tests/baselines/reference/logicalAssignment2(target=es2015).js @@ -31,12 +31,13 @@ c.foo.bar().baz ??= result.foo.bar().baz //// [logicalAssignment2.js] "use strict"; var _a, _b; -a.baz && (a.baz = result.baz); -b.baz || (b.baz = result.baz); -(_a = c.baz) !== null && _a !== void 0 ? _a : (c.baz = result.baz); -a.foo["baz"] && (a.foo["baz"] = result.foo.baz); -b.foo["baz"] && (b.foo["baz"] = result.foo.baz); -c.foo["baz"] && (c.foo["baz"] = result.foo.baz); -a.foo.bar().baz && (a.foo.bar().baz = result.foo.bar().baz); -b.foo.bar().baz || (b.foo.bar().baz = result.foo.bar().baz); -(_b = c.foo.bar().baz) !== null && _b !== void 0 ? _b : (c.foo.bar().baz = result.foo.bar().baz); +var _c, _d, _e, _f, _g, _h, _j, _k, _l; +(_c = a).baz && (_c.baz = result.baz); +(_d = b).baz || (_d.baz = result.baz); +(_a = (_e = c).baz) !== null && _a !== void 0 ? _a : (_e.baz = result.baz); +(_f = a.foo)["baz"] && (_f["baz"] = result.foo.baz); +(_g = b.foo)["baz"] && (_g["baz"] = result.foo.baz); +(_h = c.foo)["baz"] && (_h["baz"] = result.foo.baz); +(_j = a.foo.bar()).baz && (_j.baz = result.foo.bar().baz); +(_k = b.foo.bar()).baz || (_k.baz = result.foo.bar().baz); +(_b = (_l = c.foo.bar()).baz) !== null && _b !== void 0 ? _b : (_l.baz = result.foo.bar().baz); diff --git a/tests/baselines/reference/logicalAssignment2(target=es2020).js b/tests/baselines/reference/logicalAssignment2(target=es2020).js index 258de5d01e..7d4a1c1de6 100644 --- a/tests/baselines/reference/logicalAssignment2(target=es2020).js +++ b/tests/baselines/reference/logicalAssignment2(target=es2020).js @@ -30,12 +30,13 @@ c.foo.bar().baz ??= result.foo.bar().baz //// [logicalAssignment2.js] "use strict"; -a.baz && (a.baz = result.baz); -b.baz || (b.baz = result.baz); -c.baz ?? (c.baz = result.baz); -a.foo["baz"] && (a.foo["baz"] = result.foo.baz); -b.foo["baz"] && (b.foo["baz"] = result.foo.baz); -c.foo["baz"] && (c.foo["baz"] = result.foo.baz); -a.foo.bar().baz && (a.foo.bar().baz = result.foo.bar().baz); -b.foo.bar().baz || (b.foo.bar().baz = result.foo.bar().baz); -c.foo.bar().baz ?? (c.foo.bar().baz = result.foo.bar().baz); +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); diff --git a/tests/baselines/reference/logicalAssignment3(target=es2015).js b/tests/baselines/reference/logicalAssignment3(target=es2015).js index 24012130a5..47f0a21041 100644 --- a/tests/baselines/reference/logicalAssignment3(target=es2015).js +++ b/tests/baselines/reference/logicalAssignment3(target=es2015).js @@ -17,6 +17,7 @@ declare const c: A; //// [logicalAssignment3.js] "use strict"; var _a; -(a.baz) && ((a.baz) = result.baz); -(b.baz) || ((b.baz) = result.baz); -(_a = (c.baz)) !== null && _a !== void 0 ? _a : ((c.baz) = result.baz); +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); diff --git a/tests/baselines/reference/logicalAssignment3(target=es2020).js b/tests/baselines/reference/logicalAssignment3(target=es2020).js index 854fa15671..57060aea11 100644 --- a/tests/baselines/reference/logicalAssignment3(target=es2020).js +++ b/tests/baselines/reference/logicalAssignment3(target=es2020).js @@ -16,6 +16,7 @@ declare const c: A; //// [logicalAssignment3.js] "use strict"; -(a.baz) && ((a.baz) = result.baz); -(b.baz) || ((b.baz) = result.baz); -(c.baz) ?? ((c.baz) = result.baz); +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); diff --git a/tests/baselines/reference/logicalAssignment5(target=es2015).js b/tests/baselines/reference/logicalAssignment5(target=es2015).js index f42fd755c1..06fe4df0fe 100644 --- a/tests/baselines/reference/logicalAssignment5(target=es2015).js +++ b/tests/baselines/reference/logicalAssignment5(target=es2015).js @@ -33,15 +33,15 @@ function bar3 (f?: (a: number) => void) { //// [logicalAssignment5.js] "use strict"; function foo1(f) { - f !== null && f !== void 0 ? f : (f = (a => a)); + f !== null && f !== void 0 ? f : (f = a => a); f(42); } function foo2(f) { - f || (f = (a => a)); + f || (f = a => a); f(42); } function foo3(f) { - f && (f = (a => a)); + f && (f = a => a); f(42); } function bar1(f) { diff --git a/tests/baselines/reference/logicalAssignment5(target=es2020).js b/tests/baselines/reference/logicalAssignment5(target=es2020).js index 58f3a4553d..4403e390b8 100644 --- a/tests/baselines/reference/logicalAssignment5(target=es2020).js +++ b/tests/baselines/reference/logicalAssignment5(target=es2020).js @@ -33,15 +33,15 @@ function bar3 (f?: (a: number) => void) { //// [logicalAssignment5.js] "use strict"; function foo1(f) { - f ?? (f = (a => a)); + f ?? (f = a => a); f(42); } function foo2(f) { - f || (f = (a => a)); + f || (f = a => a); f(42); } function foo3(f) { - f && (f = (a => a)); + f && (f = a => a); f(42); } function bar1(f) { diff --git a/tests/baselines/reference/logicalAssignment6(target=es2015).js b/tests/baselines/reference/logicalAssignment6(target=es2015).js index a0424da177..5b002760a2 100644 --- a/tests/baselines/reference/logicalAssignment6(target=es2015).js +++ b/tests/baselines/reference/logicalAssignment6(target=es2015).js @@ -14,11 +14,11 @@ function foo3(results: number[] | undefined, results1: number[] | undefined) { //// [logicalAssignment6.js] "use strict"; function foo1(results, results1) { - (results || (results = (results1 || (results1 = [])))).push(100); + (results || (results = results1 || (results1 = []))).push(100); } function foo2(results, results1) { - (results !== null && results !== void 0 ? results : (results = (results1 !== null && results1 !== void 0 ? results1 : (results1 = [])))).push(100); + (results !== null && results !== void 0 ? results : (results = results1 !== null && results1 !== void 0 ? results1 : (results1 = []))).push(100); } function foo3(results, results1) { - (results && (results = (results1 && (results1 = [])))).push(100); + (results && (results = results1 && (results1 = []))).push(100); } diff --git a/tests/baselines/reference/logicalAssignment6(target=es2020).js b/tests/baselines/reference/logicalAssignment6(target=es2020).js index 66852828be..4d8032ddb8 100644 --- a/tests/baselines/reference/logicalAssignment6(target=es2020).js +++ b/tests/baselines/reference/logicalAssignment6(target=es2020).js @@ -14,11 +14,11 @@ function foo3(results: number[] | undefined, results1: number[] | undefined) { //// [logicalAssignment6.js] "use strict"; function foo1(results, results1) { - (results || (results = (results1 || (results1 = [])))).push(100); + (results || (results = results1 || (results1 = []))).push(100); } function foo2(results, results1) { - (results ?? (results = (results1 ?? (results1 = [])))).push(100); + (results ?? (results = results1 ?? (results1 = []))).push(100); } function foo3(results, results1) { - (results && (results = (results1 && (results1 = [])))).push(100); + (results && (results = results1 && (results1 = []))).push(100); }