Skip to content

Commit ff2c49e

Browse files
Closure Teamcopybara-github
authored andcommitted
Add support for transpilation of computed fields in RewriteClassMembers.
This change stops throwing errors when encountering computed fields in classes and properly transpiles them into assignments inside the constructor for non-static public fields or class property assignments below the class for static fields. PiperOrigin-RevId: 553629460
1 parent 6e98e56 commit ff2c49e

File tree

3 files changed

+305
-101
lines changed

3 files changed

+305
-101
lines changed

src/com/google/javascript/jscomp/NodeTraversal.java

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -651,6 +651,7 @@ private void traverseAtScope(AbstractScope<?, ?> s) {
651651
}
652652
break;
653653
case BLOCK:
654+
case SWITCH:
654655
if (callback.shouldTraverse(this, n, null)) {
655656
pushScope(s);
656657

@@ -700,16 +701,6 @@ private void traverseAtScope(AbstractScope<?, ?> s) {
700701
callback.visit(this, n, null);
701702
}
702703
break;
703-
case SWITCH:
704-
if (callback.shouldTraverse(this, n, null)) {
705-
pushScope(s);
706-
707-
traverseChildren(n);
708-
709-
popScope();
710-
callback.visit(this, n, null);
711-
}
712-
break;
713704
default:
714705
checkState(
715706
s.isGlobal() || s.isModuleScope(), "Expected global or module scope. Got: (%s)", s);
@@ -1303,6 +1294,7 @@ private static boolean isHoistScopeRootNode(Node n) {
13031294
}
13041295
return rootNode;
13051296
case MEMBER_FIELD_DEF:
1297+
case COMPUTED_FIELD_DEF:
13061298
case CLASS:
13071299
case MODULE_BODY:
13081300
case ROOT:

src/com/google/javascript/jscomp/RewriteClassMembers.java

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -89,10 +89,16 @@ public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
8989
classStack.push(new ClassRecord(n, classNameNode.getQualifiedName(), classInsertionPoint));
9090
break;
9191
case COMPUTED_FIELD_DEF:
92+
if (NodeUtil.canBeSideEffected(n.getFirstChild())) {
93+
t.report(
94+
n,
95+
TranspilationUtil.CANNOT_CONVERT_YET,
96+
"Class contains computed field with possible side effects");
97+
return false;
98+
}
9299
checkState(!classStack.isEmpty());
93-
t.report(n, TranspilationUtil.CANNOT_CONVERT_YET, "Computed fields");
94-
classStack.peek().cannotConvert = true;
95-
return false;
100+
classStack.peek().enterField(n);
101+
break;
96102
case MEMBER_FIELD_DEF:
97103
checkState(!classStack.isEmpty());
98104
classStack.peek().enterField(n);
@@ -145,12 +151,14 @@ public void visit(NodeTraversal t, Node n, Node parent) {
145151
case CLASS:
146152
visitClass(t);
147153
return;
154+
case COMPUTED_FIELD_DEF:
148155
case MEMBER_FIELD_DEF:
149156
classStack.peek().exitField();
150157
return;
151158
case THIS:
152159
Node rootNode = t.getClosestScopeRootNodeBindingThisOrSuper();
153-
if (rootNode.isMemberFieldDef() && rootNode.isStaticMember()) {
160+
if (rootNode.isStaticMember()
161+
&& (rootNode.isMemberFieldDef() || rootNode.isComputedFieldDef())) {
154162
Node className = rootNode.getGrandparent().getFirstChild().cloneNode();
155163
n.replaceWith(className);
156164
t.reportCodeChange(className);
@@ -195,7 +203,8 @@ private void rewriteInstanceMembers(NodeTraversal t, ClassRecord record) {
195203

196204
while (!instanceMembers.isEmpty()) {
197205
Node instanceMember = instanceMembers.pop();
198-
checkState(instanceMember.isMemberFieldDef());
206+
checkState(
207+
instanceMember.isMemberFieldDef() || instanceMember.isComputedFieldDef(), instanceMember);
199208

200209
for (Node nameInRhs : record.referencedNamesByMember.get(instanceMember)) {
201210
String name = nameInRhs.getString();
@@ -209,8 +218,10 @@ private void rewriteInstanceMembers(NodeTraversal t, ClassRecord record) {
209218
}
210219

211220
Node thisNode = astFactory.createThisForEs6ClassMember(instanceMember);
212-
213-
Node transpiledNode = convNonCompFieldToGetProp(thisNode, instanceMember.detach());
221+
Node transpiledNode =
222+
instanceMember.isMemberFieldDef()
223+
? convNonCompFieldToGetProp(thisNode, instanceMember.detach())
224+
: convCompFieldToGetElem(thisNode, instanceMember.detach());
214225
if (insertionPoint == ctorBlock) { // insert the field at the beginning of the block, no super
215226
ctorBlock.addChildToFront(transpiledNode);
216227
} else {
@@ -244,6 +255,9 @@ private void rewriteStaticMembers(NodeTraversal t, ClassRecord record) {
244255
case MEMBER_FIELD_DEF:
245256
transpiledNode = convNonCompFieldToGetProp(nameToUse, staticMember.detach());
246257
break;
258+
case COMPUTED_FIELD_DEF:
259+
transpiledNode = convCompFieldToGetElem(nameToUse, staticMember.detach());
260+
break;
247261
default:
248262
throw new IllegalStateException(String.valueOf(staticMember));
249263
}
@@ -272,6 +286,24 @@ private Node convNonCompFieldToGetProp(Node receiver, Node noncomputedField) {
272286
return result;
273287
}
274288

289+
/**
290+
* Creates a node that represents receiver[key] = value; where the key and value comes from the
291+
* computed field
292+
*/
293+
private Node convCompFieldToGetElem(Node receiver, Node computedField) {
294+
checkArgument(computedField.isComputedFieldDef(), computedField);
295+
checkArgument(computedField.getParent() == null, computedField);
296+
checkArgument(receiver.getParent() == null, receiver);
297+
Node getElem = astFactory.createGetElem(receiver, computedField.getFirstChild().detach());
298+
Node fieldValue = computedField.getLastChild();
299+
Node result =
300+
(fieldValue != null)
301+
? astFactory.createAssignStatement(getElem, fieldValue.detach())
302+
: astFactory.exprResult(getElem);
303+
result.srcrefTreeIfMissing(computedField);
304+
return result;
305+
}
306+
275307
/**
276308
* Finds the location in the constructor to put the transpiled instance fields
277309
*
@@ -378,7 +410,8 @@ void potentiallyRecordNameInRhs(Node nameNode) {
378410
if (currentMember == null) {
379411
return;
380412
}
381-
checkState(currentMember.isMemberFieldDef());
413+
checkState(
414+
currentMember.isMemberFieldDef() || currentMember.isComputedFieldDef(), currentMember);
382415
referencedNamesByMember.put(currentMember, nameNode);
383416
}
384417

0 commit comments

Comments
 (0)