Skip to content

Commit

Permalink
Make Es6RewriteDestructuring maintain normalization
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 538502272
  • Loading branch information
Closure Team authored and copybara-github committed Jun 7, 2023
1 parent 440be4a commit 48f192f
Show file tree
Hide file tree
Showing 2 changed files with 140 additions and 88 deletions.
83 changes: 58 additions & 25 deletions src/com/google/javascript/jscomp/Es6RewriteDestructuring.java
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ private void pullDestructuringOutOfParams(Node paramList, Node function) {
newParam =
nameOrPattern.isName()
? nameOrPattern
: astFactory.createName(getTempVariableName(), type(nameOrPattern));
: createTempVarNameNode(getTempVariableName(), type(nameOrPattern));
Node lhs = nameOrPattern.cloneTree();
Node rhs = defaultValueHook(newParam.cloneTree(), defaultValue);
Node newStatement =
Expand Down Expand Up @@ -302,10 +302,10 @@ private Node replacePatternParamWithTempVar(
Node function, Node insertSpot, Node patternParam, String tempVarName) {
// Convert `function f([a, b]) {}` to `function f(tempVar) { var [a, b] = tempVar; }`
AstFactory.Type paramType = type(patternParam);
Node newParam = astFactory.createName(tempVarName, paramType);
Node newParam = createTempVarNameNode(tempVarName, paramType);
newParam.setJSDocInfo(patternParam.getJSDocInfo());
patternParam.replaceWith(newParam);
Node newDecl = IR.var(patternParam, astFactory.createName(tempVarName, paramType));
Node newDecl = IR.var(patternParam, createTempVarNameNode(tempVarName, paramType));
newDecl.srcrefTreeIfMissing(patternParam);
if (insertSpot == null) {
function.getLastChild().addChildToFront(newDecl);
Expand All @@ -315,6 +315,18 @@ private Node replacePatternParamWithTempVar(
return newDecl;
}

/**
* Creates a new name node and adds the constant name property because a constant variable is used
* (the compiler only assigns $jscomp$destructuring$var[num] once)
*/
private Node createTempVarNameNode(String name, AstFactory.Type type) {
Node nameNode = astFactory.createName(name, type);
if (compiler.getLifeCycleStage().isNormalized()) {
nameNode.putBooleanProp(Node.IS_CONSTANT_NAME, true);
}
return nameNode;
}

/** Creates a new unique name to use for a pattern we need to rewrite. */
private String getTempVariableName() {
return DESTRUCTURING_TEMP_VAR + destructuringVarCounter++;
Expand Down Expand Up @@ -421,7 +433,7 @@ private void replaceObjectPattern(

// create the declaration `var temp = rhs;`
Node tempDecl =
IR.var(astFactory.createName(tempVarName, tempVarType), rhs.detach())
IR.var(createTempVarNameNode(tempVarName, tempVarType), rhs.detach())
.srcrefTreeIfMissing(objectPattern);
// TODO(tbreisacher): Remove the "if" and add this JSDoc unconditionally.
if (parent.isConst()) {
Expand All @@ -438,7 +450,7 @@ private void replaceObjectPattern(
final Node newRHS;
if (child.isStringKey()) {
// const {a: b} = obj;
Node tempVarNameNode = astFactory.createName(tempVarName, tempVarType);
Node tempVarNameNode = createTempVarNameNode(tempVarName, tempVarType);
Node getprop =
child.isQuotedStringKey()
? astFactory.createGetElem(
Expand Down Expand Up @@ -474,7 +486,7 @@ private void replaceObjectPattern(
// A "...rest" variable is present and result of computation must be cached
String exprEvalTempVarName = getTempVariableName();
Node exprEvalTempVarModel =
astFactory.createName(exprEvalTempVarName, type(propExpr)); // clone this node
createTempVarNameNode(exprEvalTempVarName, type(propExpr)); // clone this node
Node exprEvalDecl = IR.var(exprEvalTempVarModel.cloneNode(), propExpr);
exprEvalDecl.srcrefTreeIfMissing(child);
exprEvalDecl.insertBefore(nodeToDetach);
Expand All @@ -484,22 +496,22 @@ private void replaceObjectPattern(
if (hasDefault) {
// tempVarName[propExpr]
Node getelem =
astFactory.createGetElem(astFactory.createName(tempVarName, tempVarType), propExpr);
astFactory.createGetElem(createTempVarNameNode(tempVarName, tempVarType), propExpr);

// var tempVarName2 = tempVarName1[propExpr]
String intermediateTempVarName = getTempVariableName();
Node intermediateDecl =
IR.var(astFactory.createName(intermediateTempVarName, type(getelem)), getelem);
IR.var(createTempVarNameNode(intermediateTempVarName, type(getelem)), getelem);
intermediateDecl.srcrefTreeIfMissing(child);
intermediateDecl.insertBefore(nodeToDetach);

// tempVarName2 === undefined ? defaultValue : tempVarName2
newRHS =
defaultValueHook(
astFactory.createName(intermediateTempVarName, type(getelem)), defaultValue);
createTempVarNameNode(intermediateTempVarName, type(getelem)), defaultValue);
} else {
newRHS =
astFactory.createGetElem(astFactory.createName(tempVarName, type(newLHS)), propExpr);
astFactory.createGetElem(createTempVarNameNode(tempVarName, type(newLHS)), propExpr);
}
} else if (child.isRest()) {
if (next != null) {
Expand All @@ -511,14 +523,18 @@ private void replaceObjectPattern(
astFactory.createQName(this.namespace, "Object.assign"),
type(StandardColors.TOP_OBJECT));
assignCall.addChildToBack(astFactory.createObjectLit());
assignCall.addChildToBack(astFactory.createName(tempVarName, tempVarType));
assignCall.addChildToBack(createTempVarNameNode(tempVarName, tempVarType));

Node restTempDecl = IR.var(astFactory.createName(restTempVarName, tempVarType), assignCall);
Node restTempDecl = IR.var(createTempVarNameNode(restTempVarName, tempVarType), assignCall);
restTempDecl.srcrefTreeIfMissing(objectPattern);
restTempDecl.insertAfter(tempDecl);

Node restName = child.getOnlyChild(); // e.g. get `rest` from `const {...rest} = {};`
newLHS = astFactory.createName(restName.getString(), type(restName));
if (restName.getString().startsWith(DESTRUCTURING_TEMP_VAR)) {
newLHS = createTempVarNameNode(restName.getString(), type(restName));
} else {
newLHS = astFactory.createName(restName.getString(), type(restName));
}
newRHS = objectPatternRestRHS(objectPattern, child, restTempVarName, propsToDeleteForRest);
} else {
throw new IllegalStateException("unexpected child");
Expand Down Expand Up @@ -570,7 +586,7 @@ private void replaceObjectPattern(
private Node objectPatternRestRHS(
Node objectPattern, Node rest, String restTempVarName, ArrayList<Node> statedProperties) {
checkArgument(objectPattern.getLastChild() == rest);
Node restTempVarModel = astFactory.createName(restTempVarName, type(objectPattern));
Node restTempVarModel = createTempVarNameNode(restTempVarName, type(objectPattern));
Node result = restTempVarModel.cloneNode();
if (!statedProperties.isEmpty()) {
Iterator<Node> propItr = statedProperties.iterator();
Expand Down Expand Up @@ -665,7 +681,7 @@ private void replaceArrayPattern(
"value");
AstFactory.Type nextVarType = type(nextCallDotValue);
// `var temp1 = temp.next().value`
Node var = IR.var(astFactory.createName(nextVarName, nextVarType), nextCallDotValue);
Node var = IR.var(createTempVarNameNode(nextVarName, nextVarType), nextCallDotValue);
var.srcrefTreeIfMissing(child);
var.insertBefore(nodeToDetach);

Expand All @@ -674,7 +690,7 @@ private void replaceArrayPattern(
// `(temp1 === undefined) ? defaultValue : temp1;
newRHS =
defaultValueHook(
astFactory.createName(nextVarName, nextVarType), child.getLastChild().detach());
createTempVarNameNode(nextVarName, nextVarType), child.getLastChild().detach());
} else if (child.isRest()) {
// [...x] = rhs;
// becomes
Expand Down Expand Up @@ -746,7 +762,7 @@ private void wrapAssignOrDestructuringInCallToArrow(NodeTraversal t, Node assign
String tempVarName = getTempVariableName();
Node rhs = assignment.getLastChild().detach();

Node tempVarModel = astFactory.createName(tempVarName, type(rhs));
Node tempVarModel = createTempVarNameNode(tempVarName, type(rhs));
// let temp0 = rhs;
Node newAssignment = IR.let(tempVarModel.cloneNode(), rhs);
NodeUtil.addFeatureToScript(t.getCurrentScript(), Feature.LET_DECLARATIONS, compiler);
Expand Down Expand Up @@ -857,11 +873,11 @@ private void visitDestructuringPatternInEnhancedForInnerVars(Node pattern) {
checkState(NodeUtil.isEnhancedFor(forNode));
Node block = forNode.getLastChild();

destructuringLhs.replaceWith(astFactory.createName(tempVarName, type(pattern)).srcref(pattern));
destructuringLhs.replaceWith(createTempVarNameNode(tempVarName, type(pattern)).srcref(pattern));
Token declarationType = declarationNode.getToken();
Node decl =
IR.declaration(
pattern.detach(), astFactory.createName(tempVarName, type(pattern)), declarationType);
pattern.detach(), createTempVarNameNode(tempVarName, type(pattern)), declarationType);
decl.srcrefTreeIfMissing(pattern);
// Move the body into an inner block to handle cases where declared variables in the for
// loop initializer are shadowed by variables in the for loop body. e.g.
Expand All @@ -871,20 +887,37 @@ private void visitDestructuringPatternInEnhancedForInnerVars(Node pattern) {
newBlock.addChildToBack(block);
}

/** for ([a, b, c] of arr) */
/**
* for ([a, b, c] of arr)
*
* <pre>
* Transform
* for ({x} of y) {}
* into
* {@code var TEMP_VAR0;
* for (TEMP_VAR0 of y) {
* var TEMP_VAR1 = TEMP_VAR0;
* x = TEMP_VAR1.x;
* }}
* </pre>
*/
private void visitDestructuringPatternInEnhancedForWithOuterVars(Node pattern) {
checkArgument(pattern.isDestructuringPattern());
String tempVarName = getTempVariableName();

Node forNode = pattern.getParent();
Node block = forNode.getLastChild();

Node decl = IR.var(astFactory.createName(tempVarName, type(pattern)));
Node name = createTempVarNameNode(tempVarName, type(pattern));
Node decl = IR.var(name);
decl.srcrefTreeIfMissing(pattern);
pattern.replaceWith(decl);
decl.insertBefore(forNode);
Node clonedName = name.cloneNode();
clonedName.srcrefTreeIfMissing(pattern);
pattern.replaceWith(clonedName);
Node exprResult =
IR.exprResult(
astFactory.createAssign(pattern, astFactory.createName(tempVarName, type(pattern))));
astFactory.createAssign(pattern, createTempVarNameNode(tempVarName, type(pattern))));
exprResult.srcrefTreeIfMissing(pattern);
block.addChildToFront(exprResult);
}
Expand All @@ -894,9 +927,9 @@ private void visitDestructuringPatternInCatch(NodeTraversal t, Node pattern) {
Node catchBlock = pattern.getNext();
AstFactory.Type patternType = type(pattern);

pattern.replaceWith(astFactory.createName(tempVarName, patternType));
pattern.replaceWith(createTempVarNameNode(tempVarName, patternType));
catchBlock.addChildToFront(
IR.declaration(pattern, astFactory.createName(tempVarName, patternType), Token.LET));
IR.declaration(pattern, createTempVarNameNode(tempVarName, patternType), Token.LET));
NodeUtil.addFeatureToScript(t.getCurrentScript(), Feature.LET_DECLARATIONS, compiler);
}

Expand Down
Loading

0 comments on commit 48f192f

Please sign in to comment.