@@ -218,6 +218,9 @@ namespace ts {
218
218
// or if compiler options contain alwaysStrict.
219
219
let inStrictMode : boolean ;
220
220
221
+ // If we are binding an assignment pattern, we will bind certain expressions differently.
222
+ let inAssignmentPattern = false ;
223
+
221
224
let symbolCount = 0 ;
222
225
223
226
let Symbol : new ( flags : SymbolFlags , name : __String ) => Symbol ;
@@ -275,6 +278,7 @@ namespace ts {
275
278
currentExceptionTarget = undefined ;
276
279
activeLabelList = undefined ;
277
280
hasExplicitReturn = false ;
281
+ inAssignmentPattern = false ;
278
282
emitFlags = NodeFlags . None ;
279
283
}
280
284
@@ -733,9 +737,14 @@ namespace ts {
733
737
}
734
738
735
739
function bindChildren ( node : Node ) : void {
740
+ const saveInAssignmentPattern = inAssignmentPattern ;
741
+ // Most nodes aren't valid in an assignment pattern, so we clear the value here
742
+ // and set it before we descend into nodes that could actually be part of an assignment pattern.
743
+ inAssignmentPattern = false ;
736
744
if ( checkUnreachable ( node ) ) {
737
745
bindEachChild ( node ) ;
738
746
bindJSDoc ( node ) ;
747
+ inAssignmentPattern = saveInAssignmentPattern ;
739
748
return ;
740
749
}
741
750
if ( node . kind >= SyntaxKind . FirstStatement && node . kind <= SyntaxKind . LastStatement && ! options . allowUnreachableCode ) {
@@ -791,6 +800,13 @@ namespace ts {
791
800
bindPostfixUnaryExpressionFlow ( < PostfixUnaryExpression > node ) ;
792
801
break ;
793
802
case SyntaxKind . BinaryExpression :
803
+ if ( isDestructuringAssignment ( node ) ) {
804
+ // Carry over whether we are in an assignment pattern to
805
+ // binary expressions that could actually be an initializer
806
+ inAssignmentPattern = saveInAssignmentPattern ;
807
+ bindDestructuringAssignmentFlow ( node ) ;
808
+ return ;
809
+ }
794
810
bindBinaryExpressionFlow ( < BinaryExpression > node ) ;
795
811
break ;
796
812
case SyntaxKind . DeleteExpression :
@@ -827,11 +843,23 @@ namespace ts {
827
843
case SyntaxKind . ModuleBlock :
828
844
bindEachFunctionsFirst ( ( node as Block ) . statements ) ;
829
845
break ;
846
+ case SyntaxKind . BindingElement :
847
+ bindBindingElementFlow ( < BindingElement > node ) ;
848
+ break ;
849
+ case SyntaxKind . ObjectLiteralExpression :
850
+ case SyntaxKind . ArrayLiteralExpression :
851
+ case SyntaxKind . PropertyAssignment :
852
+ case SyntaxKind . SpreadElement :
853
+ // Carry over whether we are in an assignment pattern of Object and Array literals
854
+ // as well as their children that are valid assignment targets.
855
+ inAssignmentPattern = saveInAssignmentPattern ;
856
+ // falls through
830
857
default :
831
858
bindEachChild ( node ) ;
832
859
break ;
833
860
}
834
861
bindJSDoc ( node ) ;
862
+ inAssignmentPattern = saveInAssignmentPattern ;
835
863
}
836
864
837
865
function isNarrowingExpression ( expr : Expression ) : boolean {
@@ -1455,6 +1483,24 @@ namespace ts {
1455
1483
}
1456
1484
}
1457
1485
1486
+ function bindDestructuringAssignmentFlow ( node : DestructuringAssignment ) {
1487
+ if ( inAssignmentPattern ) {
1488
+ inAssignmentPattern = false ;
1489
+ bind ( node . operatorToken ) ;
1490
+ bind ( node . right ) ;
1491
+ inAssignmentPattern = true ;
1492
+ bind ( node . left ) ;
1493
+ }
1494
+ else {
1495
+ inAssignmentPattern = true ;
1496
+ bind ( node . left ) ;
1497
+ inAssignmentPattern = false ;
1498
+ bind ( node . operatorToken ) ;
1499
+ bind ( node . right ) ;
1500
+ }
1501
+ bindAssignmentTargetFlow ( node . left ) ;
1502
+ }
1503
+
1458
1504
const enum BindBinaryExpressionFlowState {
1459
1505
BindThenBindChildren ,
1460
1506
MaybeBindLeft ,
@@ -1571,7 +1617,7 @@ namespace ts {
1571
1617
* If `node` is a BinaryExpression, adds it to the local work stack, otherwise recursively binds it
1572
1618
*/
1573
1619
function maybeBind ( node : Node ) {
1574
- if ( node && isBinaryExpression ( node ) ) {
1620
+ if ( node && isBinaryExpression ( node ) && ! isDestructuringAssignment ( node ) ) {
1575
1621
stackIndex ++ ;
1576
1622
workStacks . expr [ stackIndex ] = node ;
1577
1623
workStacks . state [ stackIndex ] = BindBinaryExpressionFlowState . BindThenBindChildren ;
@@ -1626,6 +1672,25 @@ namespace ts {
1626
1672
}
1627
1673
}
1628
1674
1675
+ function bindBindingElementFlow ( node : BindingElement ) {
1676
+ if ( isBindingPattern ( node . name ) ) {
1677
+ // When evaluating a binding pattern, the initializer is evaluated before the binding pattern, per:
1678
+ // - https://tc39.es/ecma262/#sec-destructuring-binding-patterns-runtime-semantics-iteratorbindinginitialization
1679
+ // - `BindingElement: BindingPattern Initializer?`
1680
+ // - https://tc39.es/ecma262/#sec-runtime-semantics-keyedbindinginitialization
1681
+ // - `BindingElement: BindingPattern Initializer?`
1682
+ bindEach ( node . decorators ) ;
1683
+ bindEach ( node . modifiers ) ;
1684
+ bind ( node . dotDotDotToken ) ;
1685
+ bind ( node . propertyName ) ;
1686
+ bind ( node . initializer ) ;
1687
+ bind ( node . name ) ;
1688
+ }
1689
+ else {
1690
+ bindEachChild ( node ) ;
1691
+ }
1692
+ }
1693
+
1629
1694
function bindJSDocTypeAlias ( node : JSDocTypedefTag | JSDocCallbackTag | JSDocEnumTag ) {
1630
1695
setParent ( node . tagName , node ) ;
1631
1696
if ( node . kind !== SyntaxKind . JSDocEnumTag && node . fullName ) {
0 commit comments