@@ -59,6 +59,7 @@ namespace ts {
5959 let exportedVariableStatement = false ;
6060 let enabledSubstitutions : ESNextSubstitutionFlags ;
6161 let enclosingFunctionFlags : FunctionFlags ;
62+ let parametersWithPrecedingObjectRestOrSpread : Set < ParameterDeclaration > | undefined ;
6263 let enclosingSuperContainerFlags : NodeCheckFlags = 0 ;
6364 let hierarchyFacts : HierarchyFacts = 0 ;
6465
@@ -785,7 +786,24 @@ namespace ts {
785786 ) ;
786787 }
787788
789+ function parameterVisitor ( node : Node ) {
790+ Debug . assertNode ( node , isParameter ) ;
791+ return visitParameter ( node ) ;
792+ }
793+
788794 function visitParameter ( node : ParameterDeclaration ) : ParameterDeclaration {
795+ if ( parametersWithPrecedingObjectRestOrSpread ?. has ( node ) ) {
796+ return factory . updateParameterDeclaration (
797+ node ,
798+ /*decorators*/ undefined ,
799+ /*modifiers*/ undefined ,
800+ node . dotDotDotToken ,
801+ isBindingPattern ( node . name ) ? factory . getGeneratedNameForNode ( node ) : node . name ,
802+ /*questionToken*/ undefined ,
803+ /*type*/ undefined ,
804+ /*initializer*/ undefined
805+ ) ;
806+ }
789807 if ( node . transformFlags & TransformFlags . ContainsObjectRestOrSpread ) {
790808 // Binding patterns are converted into a generated name and are
791809 // evaluated inside the function body.
@@ -803,54 +821,78 @@ namespace ts {
803821 return visitEachChild ( node , visitor , context ) ;
804822 }
805823
824+ function collectParametersWithPrecedingObjectRestOrSpread ( node : SignatureDeclaration ) {
825+ let parameters : Set < ParameterDeclaration > | undefined ;
826+ for ( const parameter of node . parameters ) {
827+ if ( parameters ) {
828+ parameters . add ( parameter ) ;
829+ }
830+ else if ( parameter . transformFlags & TransformFlags . ContainsObjectRestOrSpread ) {
831+ parameters = new Set ( ) ;
832+ }
833+ }
834+ return parameters ;
835+ }
836+
806837 function visitConstructorDeclaration ( node : ConstructorDeclaration ) {
807838 const savedEnclosingFunctionFlags = enclosingFunctionFlags ;
808- enclosingFunctionFlags = FunctionFlags . Normal ;
839+ const savedParametersWithPrecedingObjectRestOrSpread = parametersWithPrecedingObjectRestOrSpread ;
840+ enclosingFunctionFlags = getFunctionFlags ( node ) ;
841+ parametersWithPrecedingObjectRestOrSpread = collectParametersWithPrecedingObjectRestOrSpread ( node ) ;
809842 const updated = factory . updateConstructorDeclaration (
810843 node ,
811844 /*decorators*/ undefined ,
812845 node . modifiers ,
813- visitParameterList ( node . parameters , visitor , context ) ,
846+ visitParameterList ( node . parameters , parameterVisitor , context ) ,
814847 transformFunctionBody ( node )
815848 ) ;
816849 enclosingFunctionFlags = savedEnclosingFunctionFlags ;
850+ parametersWithPrecedingObjectRestOrSpread = savedParametersWithPrecedingObjectRestOrSpread ;
817851 return updated ;
818852 }
819853
820854 function visitGetAccessorDeclaration ( node : GetAccessorDeclaration ) {
821855 const savedEnclosingFunctionFlags = enclosingFunctionFlags ;
822- enclosingFunctionFlags = FunctionFlags . Normal ;
856+ const savedParametersWithPrecedingObjectRestOrSpread = parametersWithPrecedingObjectRestOrSpread ;
857+ enclosingFunctionFlags = getFunctionFlags ( node ) ;
858+ parametersWithPrecedingObjectRestOrSpread = collectParametersWithPrecedingObjectRestOrSpread ( node ) ;
823859 const updated = factory . updateGetAccessorDeclaration (
824860 node ,
825861 /*decorators*/ undefined ,
826862 node . modifiers ,
827863 visitNode ( node . name , visitor , isPropertyName ) ,
828- visitParameterList ( node . parameters , visitor , context ) ,
864+ visitParameterList ( node . parameters , parameterVisitor , context ) ,
829865 /*type*/ undefined ,
830866 transformFunctionBody ( node )
831867 ) ;
832868 enclosingFunctionFlags = savedEnclosingFunctionFlags ;
869+ parametersWithPrecedingObjectRestOrSpread = savedParametersWithPrecedingObjectRestOrSpread ;
833870 return updated ;
834871 }
835872
836873 function visitSetAccessorDeclaration ( node : SetAccessorDeclaration ) {
837874 const savedEnclosingFunctionFlags = enclosingFunctionFlags ;
838- enclosingFunctionFlags = FunctionFlags . Normal ;
875+ const savedParametersWithPrecedingObjectRestOrSpread = parametersWithPrecedingObjectRestOrSpread ;
876+ enclosingFunctionFlags = getFunctionFlags ( node ) ;
877+ parametersWithPrecedingObjectRestOrSpread = collectParametersWithPrecedingObjectRestOrSpread ( node ) ;
839878 const updated = factory . updateSetAccessorDeclaration (
840879 node ,
841880 /*decorators*/ undefined ,
842881 node . modifiers ,
843882 visitNode ( node . name , visitor , isPropertyName ) ,
844- visitParameterList ( node . parameters , visitor , context ) ,
883+ visitParameterList ( node . parameters , parameterVisitor , context ) ,
845884 transformFunctionBody ( node )
846885 ) ;
847886 enclosingFunctionFlags = savedEnclosingFunctionFlags ;
887+ parametersWithPrecedingObjectRestOrSpread = savedParametersWithPrecedingObjectRestOrSpread ;
848888 return updated ;
849889 }
850890
851891 function visitMethodDeclaration ( node : MethodDeclaration ) {
852892 const savedEnclosingFunctionFlags = enclosingFunctionFlags ;
893+ const savedParametersWithPrecedingObjectRestOrSpread = parametersWithPrecedingObjectRestOrSpread ;
853894 enclosingFunctionFlags = getFunctionFlags ( node ) ;
895+ parametersWithPrecedingObjectRestOrSpread = collectParametersWithPrecedingObjectRestOrSpread ( node ) ;
854896 const updated = factory . updateMethodDeclaration (
855897 node ,
856898 /*decorators*/ undefined ,
@@ -863,19 +905,22 @@ namespace ts {
863905 visitNode ( node . name , visitor , isPropertyName ) ,
864906 visitNode < Token < SyntaxKind . QuestionToken > > ( /*questionToken*/ undefined , visitor , isToken ) ,
865907 /*typeParameters*/ undefined ,
866- visitParameterList ( node . parameters , visitor , context ) ,
908+ visitParameterList ( node . parameters , parameterVisitor , context ) ,
867909 /*type*/ undefined ,
868910 enclosingFunctionFlags & FunctionFlags . Async && enclosingFunctionFlags & FunctionFlags . Generator
869911 ? transformAsyncGeneratorFunctionBody ( node )
870912 : transformFunctionBody ( node )
871913 ) ;
872914 enclosingFunctionFlags = savedEnclosingFunctionFlags ;
915+ parametersWithPrecedingObjectRestOrSpread = savedParametersWithPrecedingObjectRestOrSpread ;
873916 return updated ;
874917 }
875918
876919 function visitFunctionDeclaration ( node : FunctionDeclaration ) {
877920 const savedEnclosingFunctionFlags = enclosingFunctionFlags ;
921+ const savedParametersWithPrecedingObjectRestOrSpread = parametersWithPrecedingObjectRestOrSpread ;
878922 enclosingFunctionFlags = getFunctionFlags ( node ) ;
923+ parametersWithPrecedingObjectRestOrSpread = collectParametersWithPrecedingObjectRestOrSpread ( node ) ;
879924 const updated = factory . updateFunctionDeclaration (
880925 node ,
881926 /*decorators*/ undefined ,
@@ -887,35 +932,41 @@ namespace ts {
887932 : node . asteriskToken ,
888933 node . name ,
889934 /*typeParameters*/ undefined ,
890- visitParameterList ( node . parameters , visitor , context ) ,
935+ visitParameterList ( node . parameters , parameterVisitor , context ) ,
891936 /*type*/ undefined ,
892937 enclosingFunctionFlags & FunctionFlags . Async && enclosingFunctionFlags & FunctionFlags . Generator
893938 ? transformAsyncGeneratorFunctionBody ( node )
894939 : transformFunctionBody ( node )
895940 ) ;
896941 enclosingFunctionFlags = savedEnclosingFunctionFlags ;
942+ parametersWithPrecedingObjectRestOrSpread = savedParametersWithPrecedingObjectRestOrSpread ;
897943 return updated ;
898944 }
899945
900946 function visitArrowFunction ( node : ArrowFunction ) {
901947 const savedEnclosingFunctionFlags = enclosingFunctionFlags ;
948+ const savedParametersWithPrecedingObjectRestOrSpread = parametersWithPrecedingObjectRestOrSpread ;
902949 enclosingFunctionFlags = getFunctionFlags ( node ) ;
950+ parametersWithPrecedingObjectRestOrSpread = collectParametersWithPrecedingObjectRestOrSpread ( node ) ;
903951 const updated = factory . updateArrowFunction (
904952 node ,
905953 node . modifiers ,
906954 /*typeParameters*/ undefined ,
907- visitParameterList ( node . parameters , visitor , context ) ,
955+ visitParameterList ( node . parameters , parameterVisitor , context ) ,
908956 /*type*/ undefined ,
909957 node . equalsGreaterThanToken ,
910958 transformFunctionBody ( node ) ,
911959 ) ;
912960 enclosingFunctionFlags = savedEnclosingFunctionFlags ;
961+ parametersWithPrecedingObjectRestOrSpread = savedParametersWithPrecedingObjectRestOrSpread ;
913962 return updated ;
914963 }
915964
916965 function visitFunctionExpression ( node : FunctionExpression ) {
917966 const savedEnclosingFunctionFlags = enclosingFunctionFlags ;
967+ const savedParametersWithPrecedingObjectRestOrSpread = parametersWithPrecedingObjectRestOrSpread ;
918968 enclosingFunctionFlags = getFunctionFlags ( node ) ;
969+ parametersWithPrecedingObjectRestOrSpread = collectParametersWithPrecedingObjectRestOrSpread ( node ) ;
919970 const updated = factory . updateFunctionExpression (
920971 node ,
921972 enclosingFunctionFlags & FunctionFlags . Generator
@@ -926,13 +977,14 @@ namespace ts {
926977 : node . asteriskToken ,
927978 node . name ,
928979 /*typeParameters*/ undefined ,
929- visitParameterList ( node . parameters , visitor , context ) ,
980+ visitParameterList ( node . parameters , parameterVisitor , context ) ,
930981 /*type*/ undefined ,
931982 enclosingFunctionFlags & FunctionFlags . Async && enclosingFunctionFlags & FunctionFlags . Generator
932983 ? transformAsyncGeneratorFunctionBody ( node )
933984 : transformFunctionBody ( node )
934985 ) ;
935986 enclosingFunctionFlags = savedEnclosingFunctionFlags ;
987+ parametersWithPrecedingObjectRestOrSpread = savedParametersWithPrecedingObjectRestOrSpread ;
936988 return updated ;
937989 }
938990
@@ -1007,6 +1059,7 @@ namespace ts {
10071059 statementOffset = factory . copyPrologue ( body . statements , statements , /*ensureUseStrict*/ false , visitor ) ;
10081060 }
10091061 addRange ( statements , appendObjectRestAssignmentsIfNeeded ( /*statements*/ undefined , node ) ) ;
1062+
10101063 const leadingStatements = endLexicalEnvironment ( ) ;
10111064 if ( statementOffset > 0 || some ( statements ) || some ( leadingStatements ) ) {
10121065 const block = factory . converters . convertToFunctionBlock ( body , /*multiLine*/ true ) ;
@@ -1018,25 +1071,86 @@ namespace ts {
10181071 }
10191072
10201073 function appendObjectRestAssignmentsIfNeeded ( statements : Statement [ ] | undefined , node : FunctionLikeDeclaration ) : Statement [ ] | undefined {
1074+ let containsPrecedingObjectRestOrSpread = false ;
10211075 for ( const parameter of node . parameters ) {
1022- if ( parameter . transformFlags & TransformFlags . ContainsObjectRestOrSpread ) {
1023- const temp = factory . getGeneratedNameForNode ( parameter ) ;
1076+ if ( containsPrecedingObjectRestOrSpread ) {
1077+ if ( isBindingPattern ( parameter . name ) ) {
1078+ // In cases where a binding pattern is simply '[]' or '{}',
1079+ // we usually don't want to emit a var declaration; however, in the presence
1080+ // of an initializer, we must emit that expression to preserve side effects.
1081+ //
1082+ // NOTE: see `insertDefaultValueAssignmentForBindingPattern` in es2015.ts
1083+ if ( parameter . name . elements . length > 0 ) {
1084+ const declarations = flattenDestructuringBinding (
1085+ parameter ,
1086+ visitor ,
1087+ context ,
1088+ FlattenLevel . All ,
1089+ factory . getGeneratedNameForNode ( parameter ) ) ;
1090+ if ( some ( declarations ) ) {
1091+ const declarationList = factory . createVariableDeclarationList ( declarations ) ;
1092+ const statement = factory . createVariableStatement ( /*modifiers*/ undefined , declarationList ) ;
1093+ setEmitFlags ( statement , EmitFlags . CustomPrologue ) ;
1094+ statements = append ( statements , statement ) ;
1095+ }
1096+ }
1097+ else if ( parameter . initializer ) {
1098+ const name = factory . getGeneratedNameForNode ( parameter ) ;
1099+ const initializer = visitNode ( parameter . initializer , visitor , isExpression ) ;
1100+ const assignment = factory . createAssignment ( name , initializer ) ;
1101+ const statement = factory . createExpressionStatement ( assignment ) ;
1102+ setEmitFlags ( statement , EmitFlags . CustomPrologue ) ;
1103+ statements = append ( statements , statement ) ;
1104+ }
1105+ }
1106+ else if ( parameter . initializer ) {
1107+ // Converts a parameter initializer into a function body statement, i.e.:
1108+ //
1109+ // function f(x = 1) { }
1110+ //
1111+ // becomes
1112+ //
1113+ // function f(x) {
1114+ // if (typeof x === "undefined") { x = 1; }
1115+ // }
1116+
1117+ const name = factory . cloneNode ( parameter . name ) ;
1118+ setTextRange ( name , parameter . name ) ;
1119+ setEmitFlags ( name , EmitFlags . NoSourceMap ) ;
1120+
1121+ const initializer = visitNode ( parameter . initializer , visitor , isExpression ) ;
1122+ addEmitFlags ( initializer , EmitFlags . NoSourceMap | EmitFlags . NoComments ) ;
1123+
1124+ const assignment = factory . createAssignment ( name , initializer ) ;
1125+ setTextRange ( assignment , parameter ) ;
1126+ setEmitFlags ( assignment , EmitFlags . NoComments ) ;
1127+
1128+ const block = factory . createBlock ( [ factory . createExpressionStatement ( assignment ) ] ) ;
1129+ setTextRange ( block , parameter ) ;
1130+ setEmitFlags ( block , EmitFlags . SingleLine | EmitFlags . NoTrailingSourceMap | EmitFlags . NoTokenSourceMaps | EmitFlags . NoComments ) ;
1131+
1132+ const typeCheck = factory . createTypeCheck ( factory . cloneNode ( parameter . name ) , "undefined" ) ;
1133+ const statement = factory . createIfStatement ( typeCheck , block ) ;
1134+ startOnNewLine ( statement ) ;
1135+ setTextRange ( statement , parameter ) ;
1136+ setEmitFlags ( statement , EmitFlags . NoTokenSourceMaps | EmitFlags . NoTrailingSourceMap | EmitFlags . CustomPrologue | EmitFlags . NoComments ) ;
1137+ statements = append ( statements , statement ) ;
1138+ }
1139+ }
1140+ else if ( parameter . transformFlags & TransformFlags . ContainsObjectRestOrSpread ) {
1141+ containsPrecedingObjectRestOrSpread = true ;
10241142 const declarations = flattenDestructuringBinding (
10251143 parameter ,
10261144 visitor ,
10271145 context ,
10281146 FlattenLevel . ObjectRest ,
1029- temp ,
1147+ factory . getGeneratedNameForNode ( parameter ) ,
10301148 /*doNotRecordTempVariablesInLine*/ false ,
10311149 /*skipInitializer*/ true ,
10321150 ) ;
10331151 if ( some ( declarations ) ) {
1034- const statement = factory . createVariableStatement (
1035- /*modifiers*/ undefined ,
1036- factory . createVariableDeclarationList (
1037- declarations
1038- )
1039- ) ;
1152+ const declarationList = factory . createVariableDeclarationList ( declarations ) ;
1153+ const statement = factory . createVariableStatement ( /*modifiers*/ undefined , declarationList ) ;
10401154 setEmitFlags ( statement , EmitFlags . CustomPrologue ) ;
10411155 statements = append ( statements , statement ) ;
10421156 }
0 commit comments