@@ -93,10 +93,12 @@ private void visitRestParam(NodeTraversal t, Node restParam, Node paramList) {
93
93
return ;
94
94
}
95
95
96
+ // Now that the restParam is deleted, create a let declaration by making a new NAME node of the
97
+ // same name `paramName`
96
98
Node let =
97
99
astFactory
98
100
.createSingleLetNameDeclaration (
99
- paramName ,
101
+ paramName , // creates a new NAME node with name `paramName`
100
102
astFactory .createCall (
101
103
astFactory .createGetPropWithUnknownType (
102
104
astFactory .createQName (this .namespace , "$jscomp.getRestArguments" ),
@@ -105,24 +107,37 @@ private void visitRestParam(NodeTraversal t, Node restParam, Node paramList) {
105
107
astFactory .createNumber (restIndex ),
106
108
astFactory .createArgumentsReference ()))
107
109
.srcrefTreeIfMissing (functionBody );
108
- if (paramName .startsWith ("$jscomp$destructuring$var" )) {
109
- // Currently this pass is before normalization. Hence, the createSingleLetNameDeclaration
110
- // creates a non-const names. But the earlier Es6RewriteDesctructuring pass creates these
111
- // names as const names.
112
- // TODO(b/197349249): When this pass moves post normalization, stop explictly marking these
113
- // names as const in this if-block.
114
- checkState (
115
- nameNode .getBooleanProp (Node .IS_CONSTANT_NAME ),
116
- "The $jscomp$destructuring$var[num] name must've been marked as const by the"
117
- + " Es6RewriteDesctructuring pass" );
118
- let .getFirstChild ().putBooleanProp (Node .IS_CONSTANT_NAME , true );
110
+ Node insertBeforePoint = getInsertBeforePoint (functionBody );
111
+ if (insertBeforePoint != null ) {
112
+ let .insertBefore (insertBeforePoint );
113
+ } else {
114
+ // functionBody only contains hoisted function declarations
115
+ functionBody .addChildToBack (let );
119
116
}
120
- functionBody .addChildToFront (let );
121
117
NodeUtil .addFeatureToScript (t .getCurrentScript (), Feature .LET_DECLARATIONS , compiler );
122
118
compiler .ensureLibraryInjected ("es6/util/restarguments" , /* force= */ false );
123
119
t .reportCodeChange ();
124
120
}
125
121
122
+ /**
123
+ * Gets an insertion point in the function body before which we want to insert the new let
124
+ * declaration. If there's not good insertion point (e.g. the function is empty or only contains
125
+ * inner function declarations), return null.
126
+ */
127
+ private Node getInsertBeforePoint (Node functionBody ) {
128
+ checkState (functionBody .getParent ().isFunction ());
129
+ Node current = functionBody .getFirstChild ();
130
+
131
+ // Do not insert the let declaration before any hoisted function declarations in this function
132
+ // body as those function declarations are hoisted by normalization. We must maintain
133
+ // normalization.
134
+ while (current != null && NodeUtil .isFunctionDeclaration (current )) {
135
+ current = current .getNext ();
136
+ }
137
+
138
+ return current ;
139
+ }
140
+
126
141
/**
127
142
* Processes array literals or calls to eliminate spreads.
128
143
*
0 commit comments