@@ -229,14 +229,39 @@ namespace ts {
229229 if ( node . transformFlags & TransformFlags . ContainsObjectRestOrSpread ) {
230230 // spread elements emit like so:
231231 // non-spread elements are chunked together into object literals, and then all are passed to __assign:
232- // { a, ...o, b } => __assign({a}, o, {b});
232+ // { a, ...o, b } => __assign(__assign( {a}, o) , {b});
233233 // If the first element is a spread element, then the first argument to __assign is {}:
234- // { ...o, a, b, ...o2 } => __assign({}, o, {a, b}, o2)
234+ // { ...o, a, b, ...o2 } => __assign(__assign(__assign({}, o), {a, b}), o2)
235+ //
236+ // We cannot call __assign with more than two elements, since any element could cause side effects. For
237+ // example:
238+ // var k = { a: 1, b: 2 };
239+ // var o = { a: 3, ...k, b: k.a++ };
240+ // // expected: { a: 1, b: 1 }
241+ // If we translate the above to `__assign({ a: 3 }, k, { b: k.a++ })`, the `k.a++` will evaluate before
242+ // `k` is spread and we end up with `{ a: 2, b: 1 }`.
243+ //
244+ // This also occurs for spread elements, not just property assignments:
245+ // var k = { a: 1, get b() { l = { z: 9 }; return 2; } };
246+ // var l = { c: 3 };
247+ // var o = { ...k, ...l };
248+ // // expected: { a: 1, b: 2, z: 9 }
249+ // If we translate the above to `__assign({}, k, l)`, the `l` will evaluate before `k` is spread and we
250+ // end up with `{ a: 1, b: 2, c: 3 }`
235251 const objects = chunkObjectLiteralElements ( node . properties ) ;
236252 if ( objects . length && objects [ 0 ] . kind !== SyntaxKind . ObjectLiteralExpression ) {
237253 objects . unshift ( createObjectLiteral ( ) ) ;
238254 }
239- return createAssignHelper ( context , objects ) ;
255+ let expression : Expression = objects [ 0 ] ;
256+ if ( objects . length > 1 ) {
257+ for ( let i = 1 ; i < objects . length ; i ++ ) {
258+ expression = createAssignHelper ( context , [ expression , objects [ i ] ] ) ;
259+ }
260+ return expression ;
261+ }
262+ else {
263+ return createAssignHelper ( context , objects ) ;
264+ }
240265 }
241266 return visitEachChild ( node , visitor , context ) ;
242267 }
0 commit comments