@@ -218,6 +218,9 @@ namespace ts {
218218 // or if compiler options contain alwaysStrict.
219219 let inStrictMode : boolean ;
220220
221+ // If we are binding an assignment pattern, we will bind certain expressions differently.
222+ let inAssignmentPattern = false ;
223+
221224 let symbolCount = 0 ;
222225
223226 let Symbol : new ( flags : SymbolFlags , name : __String ) => Symbol ;
@@ -275,6 +278,7 @@ namespace ts {
275278 currentExceptionTarget = undefined ;
276279 activeLabelList = undefined ;
277280 hasExplicitReturn = false ;
281+ inAssignmentPattern = false ;
278282 emitFlags = NodeFlags . None ;
279283 }
280284
@@ -733,9 +737,14 @@ namespace ts {
733737 }
734738
735739 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 ;
736744 if ( checkUnreachable ( node ) ) {
737745 bindEachChild ( node ) ;
738746 bindJSDoc ( node ) ;
747+ inAssignmentPattern = saveInAssignmentPattern ;
739748 return ;
740749 }
741750 if ( node . kind >= SyntaxKind . FirstStatement && node . kind <= SyntaxKind . LastStatement && ! options . allowUnreachableCode ) {
@@ -791,6 +800,13 @@ namespace ts {
791800 bindPostfixUnaryExpressionFlow ( < PostfixUnaryExpression > node ) ;
792801 break ;
793802 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+ }
794810 bindBinaryExpressionFlow ( < BinaryExpression > node ) ;
795811 break ;
796812 case SyntaxKind . DeleteExpression :
@@ -827,11 +843,23 @@ namespace ts {
827843 case SyntaxKind . ModuleBlock :
828844 bindEachFunctionsFirst ( ( node as Block ) . statements ) ;
829845 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
830857 default :
831858 bindEachChild ( node ) ;
832859 break ;
833860 }
834861 bindJSDoc ( node ) ;
862+ inAssignmentPattern = saveInAssignmentPattern ;
835863 }
836864
837865 function isNarrowingExpression ( expr : Expression ) : boolean {
@@ -1455,6 +1483,24 @@ namespace ts {
14551483 }
14561484 }
14571485
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+
14581504 const enum BindBinaryExpressionFlowState {
14591505 BindThenBindChildren ,
14601506 MaybeBindLeft ,
@@ -1571,7 +1617,7 @@ namespace ts {
15711617 * If `node` is a BinaryExpression, adds it to the local work stack, otherwise recursively binds it
15721618 */
15731619 function maybeBind ( node : Node ) {
1574- if ( node && isBinaryExpression ( node ) ) {
1620+ if ( node && isBinaryExpression ( node ) && ! isDestructuringAssignment ( node ) ) {
15751621 stackIndex ++ ;
15761622 workStacks . expr [ stackIndex ] = node ;
15771623 workStacks . state [ stackIndex ] = BindBinaryExpressionFlowState . BindThenBindChildren ;
@@ -1626,6 +1672,25 @@ namespace ts {
16261672 }
16271673 }
16281674
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+
16291694 function bindJSDocTypeAlias ( node : JSDocTypedefTag | JSDocCallbackTag | JSDocEnumTag ) {
16301695 setParent ( node . tagName , node ) ;
16311696 if ( node . kind !== SyntaxKind . JSDocEnumTag && node . fullName ) {
0 commit comments