private void visitObjectWithComputedProperty(Node obj) {
    checkArgument(obj.isObjectLit());
    List<Node> props = new ArrayList<>();
    Node currElement = obj.getFirstChild();
    JSType objectType = obj.getJSType();

    while (currElement != null) {
      if (currElement.getBooleanProp(Node.COMPUTED_PROP_GETTER)
          || currElement.getBooleanProp(Node.COMPUTED_PROP_SETTER)) {
        Es6ToEs3Util.cannotConvertYet(
            compiler, currElement, "computed getter/setter in an object literal");
        return;
      } else if (currElement.isGetterDef() || currElement.isSetterDef()) {
        currElement = currElement.getNext();
      } else {
        Node nextNode = currElement.getNext();
        obj.removeChild(currElement);
        props.add(currElement);
        currElement = nextNode;
      }
    }

    String objName = FRESH_COMP_PROP_VAR + compiler.getUniqueNameIdSupplier().get();

    props = Lists.reverse(props);
    Node result = withType(IR.name(objName), objectType);
    for (Node propdef : props) {
      if (propdef.isComputedProp()) {
        Node propertyExpression = propdef.removeFirstChild();
        Node value = propdef.removeFirstChild();
        JSType valueType = value.getJSType();
        result =
            withType(
                IR.comma(
                    withType(
                        IR.assign(
                            withUnknownType(
                                IR.getelem(
                                    withType(IR.name(objName), objectType), propertyExpression)),
                            value),
                        valueType),
                    result),
                objectType);
      } else {
        Node val = propdef.removeFirstChild();
        JSType valueType = val.getJSType();
        propdef.setToken(Token.STRING);
        propdef.setJSType(stringType);
        Token token = propdef.isQuotedString() ? Token.GETELEM : Token.GETPROP;
        Node access =
            withType(new Node(token, withType(IR.name(objName), objectType), propdef), valueType);
        result =
            withType(IR.comma(withType(IR.assign(access, val), valueType), result), objectType);
      }
    }

    Node statement = obj;
    while (!NodeUtil.isStatement(statement)) {
      statement = statement.getParent();
    }

    result.useSourceInfoIfMissingFromForTree(obj);
    obj.replaceWith(result);

    JSType simpleObjectType = createType(
        addTypes, registry, JSTypeNative.EMPTY_OBJECT_LITERAL_TYPE);
    Node var = IR.var(withType(IR.name(objName), objectType), withType(obj, simpleObjectType));
    var.useSourceInfoIfMissingFromForTree(statement);
    statement.getParent().addChildBefore(var, statement);
    compiler.reportChangeToEnclosingScope(var);
  }
private void visitObjectWithComputedProperty ( Node obj ) { checkArgument ( obj . isObjectLit ( ) ) ; List < Node > props = new ArrayList < > ( ) ; Node currElement = obj . getFirstChild ( ) ; JSType objectType = obj . getJSType ( ) ; while ( currElement != null ) { if ( currElement . getBooleanProp ( Node . COMPUTED_PROP_GETTER ) || currElement . getBooleanProp ( Node . COMPUTED_PROP_SETTER ) ) { Es6ToEs3Util . cannotConvertYet ( compiler , currElement , "computed getter/setter in an object literal" ) ; return ; } else if ( currElement . isGetterDef ( ) || currElement . isSetterDef ( ) ) { currElement = currElement . getNext ( ) ; } else { Node nextNode = currElement . getNext ( ) ; obj . removeChild ( currElement ) ; props . add ( currElement ) ; currElement = nextNode ; } } String objName = FRESH_COMP_PROP_VAR + compiler . getUniqueNameIdSupplier ( ) . get ( ) ; props = Lists . reverse ( props ) ; Node result = withType ( IR . name ( objName ) , objectType ) ; for ( Node propdef : props ) { if ( propdef . isComputedProp ( ) ) { Node propertyExpression = propdef . removeFirstChild ( ) ; Node value = propdef . removeFirstChild ( ) ; JSType valueType = value . getJSType ( ) ; result = withType ( IR . comma ( withType ( IR . assign ( withUnknownType ( IR . getelem ( withType ( IR . name ( objName ) , objectType ) , propertyExpression ) ) , value ) , valueType ) , result ) , objectType ) ; } else { Node val = propdef . removeFirstChild ( ) ; JSType valueType = val . getJSType ( ) ; propdef . setToken ( Token . STRING ) ; propdef . setJSType ( stringType ) ; Token token = propdef . isQuotedString ( ) ? Token . GETELEM : Token . GETPROP ; Node access = withType ( new Node ( token , withType ( IR . name ( objName ) , objectType ) , propdef ) , valueType ) ; result = withType ( IR . comma ( withType ( IR . assign ( access , val ) , valueType ) , result ) , objectType ) ; } } Node statement = obj ; while ( ! NodeUtil . isStatement ( statement ) ) { statement = statement . getParent ( ) ; } result . useSourceInfoIfMissingFromForTree ( obj ) ; obj . replaceWith ( result ) ; JSType simpleObjectType = createType ( addTypes , registry , JSTypeNative . EMPTY_OBJECT_LITERAL_TYPE ) ; Node var = IR . var ( withType ( IR . name ( objName ) , objectType ) , withType ( obj , simpleObjectType ) ) ; var . useSourceInfoIfMissingFromForTree ( statement ) ; statement . getParent ( ) . addChildBefore ( var , statement ) ; compiler . reportChangeToEnclosingScope ( var ) ; }
Transpiles an object node with computed property,
and add type information to the new nodes if this pass ran after type checking.
For example,<pre>   {@code
var obj = {a: 1, [i++]: 2}
is transpiled to
var $jscomp$compprop0 = {};
var obj = ($jscomp$compprop0.a = 1, ($jscomp$compprop0[i++] = 2, $jscomp$compprop0));
}</pre>
Note that when adding type information to the nodes, the NAME node $jscomp$compprop0
would always be assigned the type of the entire object (in the above example {a: number}).
This is because we do not have sufficient type information during transpilation to know,
for example, $jscomp$compprop0 has type Object{} in the expression $jscomp$compprop0.a = 1