@@ -18,22 +18,29 @@ namespace ts {
1818 recordTempVariable : ( node : Identifier ) => void ,
1919 visitor ?: ( node : Node ) => Node ) {
2020
21- let location : TextRange = node ;
22- let value = node . right ;
2321 if ( isEmptyObjectLiteralOrArrayLiteral ( node . left ) ) {
24- return value ;
22+ return node . right ;
2523 }
2624
25+ let location : TextRange = node ;
26+ let value = node . right ;
2727 const expressions : Expression [ ] = [ ] ;
2828 if ( needsValue ) {
29- // Temporary assignment needed to emit root should highlight whole binary expression
30- value = ensureIdentifier ( node . right , /*reuseIdentifierExpressions*/ true , node , emitTempVariableAssignment ) ;
29+ // If the right-hand value of the destructuring assignment needs to be preserved (as
30+ // is the case when the destructuring assignmen) is part of a larger expression),
31+ // then we need to cache the right-hand value.
32+ //
33+ // The source map location for the assignment should point to the entire binary
34+ // expression.
35+ value = ensureIdentifier ( node . right , /*reuseIdentifierExpressions*/ true , location , emitTempVariableAssignment ) ;
3136 }
3237 else if ( nodeIsSynthesized ( node ) ) {
33- // Source map node for root.left = root.right is root
34- // but if root is synthetic, which could be in below case, use the target which is { a }
35- // for ({a} of {a: string}) {
36- // }
38+ // Generally, the source map location for a destructuring assignment is the root
39+ // expression.
40+ //
41+ // However, if the root expression is synthesized (as in the case
42+ // of the initializer when transforming a ForOfStatement), then the source map
43+ // location should point to the right-hand value of the expression.
3744 location = node . right ;
3845 }
3946
@@ -255,21 +262,22 @@ namespace ts {
255262
256263 function emitArrayLiteralAssignment ( target : ArrayLiteralExpression , value : Expression , location : TextRange ) {
257264 const elements = target . elements ;
258- if ( elements . length !== 1 ) {
265+ const numElements = elements . length ;
266+ if ( numElements !== 1 ) {
259267 // For anything but a single element destructuring we need to generate a temporary
260268 // to ensure value is evaluated exactly once.
261269 // When doing so we want to hightlight the passed in source map node since thats the one needing this temp assignment
262270 value = ensureIdentifier ( value , /*reuseIdentifierExpressions*/ true , location , emitTempVariableAssignment ) ;
263271 }
264272
265- for ( let i = 0 ; i < elements . length ; i ++ ) {
273+ for ( let i = 0 ; i < numElements ; i ++ ) {
266274 const e = elements [ i ] ;
267275 if ( e . kind !== SyntaxKind . OmittedExpression ) {
268276 // Assignment for target = value.propName should highligh whole property, hence use e as source map node
269277 if ( e . kind !== SyntaxKind . SpreadElementExpression ) {
270278 emitDestructuringAssignment ( e , createElementAccess ( value , createLiteral ( i ) ) , e ) ;
271279 }
272- else if ( i === elements . length - 1 ) {
280+ else if ( i === numElements - 1 ) {
273281 emitDestructuringAssignment ( ( < SpreadElementExpression > e ) . expression , createArraySlice ( value , i ) , e ) ;
274282 }
275283 }
@@ -299,19 +307,19 @@ namespace ts {
299307 // so in that case, we'll intentionally create that temporary.
300308 value = ensureIdentifier ( value , /*reuseIdentifierExpressions*/ numElements !== 0 , target , emitTempVariableAssignment ) ;
301309 }
302- for ( let i = 0 ; i < elements . length ; i ++ ) {
303- let element = elements [ i ] ;
310+ for ( let i = 0 ; i < numElements ; i ++ ) {
311+ const element = elements [ i ] ;
304312 if ( name . kind === SyntaxKind . ObjectBindingPattern ) {
305313 // Rewrite element to a declaration with an initializer that fetches property
306- let propName = element . propertyName || < Identifier > element . name ;
314+ const propName = element . propertyName || < Identifier > element . name ;
307315 emitBindingElement ( element , createDestructuringPropertyAccess ( value , propName ) ) ;
308316 }
309317 else if ( element . kind !== SyntaxKind . OmittedExpression ) {
310318 if ( ! element . dotDotDotToken ) {
311319 // Rewrite element to a declaration that accesses array element at index i
312320 emitBindingElement ( element , createElementAccess ( value , i ) ) ;
313321 }
314- else if ( i === elements . length - 1 ) {
322+ else if ( i === numElements - 1 ) {
315323 emitBindingElement ( element , createArraySlice ( value , i ) ) ;
316324 }
317325 }
@@ -332,24 +340,31 @@ namespace ts {
332340 ) ;
333341 }
334342
335- function createDestructuringPropertyAccess ( object : Expression , propertyName : PropertyName ) : LeftHandSideExpression {
343+ /**
344+ * Creates either a PropertyAccessExpression or an ElementAccessExpression for the
345+ * right-hand side of a transformed destructuring assignment.
346+ *
347+ * @param expression The right-hand expression that is the source of the property.
348+ * @param propertyName The destructuring property name.
349+ */
350+ function createDestructuringPropertyAccess ( expression : Expression , propertyName : PropertyName ) : LeftHandSideExpression {
336351 if ( isComputedPropertyName ( propertyName ) ) {
337352 return createElementAccess (
338- object ,
339- ensureIdentifier ( propertyName . expression , /*reuseIdentifierExpressions*/ false , propertyName , emitTempVariableAssignment )
353+ expression ,
354+ ensureIdentifier ( propertyName . expression , /*reuseIdentifierExpressions*/ false , /*location*/ propertyName , emitTempVariableAssignment )
340355 ) ;
341356 }
342357 else if ( isIdentifier ( propertyName ) ) {
343358 return createPropertyAccess (
344- object ,
359+ expression ,
345360 propertyName . text
346361 ) ;
347362 }
348363 else {
349364 // We create a synthetic copy of the identifier in order to avoid the rewriting that might
350365 // otherwise occur when the identifier is emitted.
351366 return createElementAccess (
352- object ,
367+ expression ,
353368 cloneNode ( propertyName )
354369 ) ;
355370 }
0 commit comments