/*
  * The APIs with an extra argument is used whenever there are two references to the same variable which
  * are optimized in one access: e.g "a = a + 1" optimized into "a++".
  */
 public void generateCompoundAssignment(
     BlockScope currentScope,
     MethodBinding writeAccessor,
     Expression expression,
     int operator,
     int assignmentImplicitConversion,
     boolean valueRequired) {
   switch (this.bits & ASTNode.RestrictiveFlagMASK) {
     case Binding.FIELD: // assigning to a field
       break;
     case Binding.LOCAL: // assigning to a local variable (cannot assign to outer local)
       LocalVariableBinding localBinding = (LocalVariableBinding) this.binding;
       // using incr bytecode if possible
       Constant assignConstant;
       switch (localBinding.type.id) {
         case T_JavaLangString:
           return;
         case T_int:
           assignConstant = expression.constant;
           if (localBinding.resolvedPosition == -1) {
             if (valueRequired) {
               /*
                * restart code gen because we either:
                * - need the value
                * - the constant can have potential side-effect
                */
               localBinding.useFlag = LocalVariableBinding.USED;
               throw new AbortMethod(null, null);
             } else if (assignConstant == Constant.NotAConstant) {
               // we only need to generate the value of the expression's constant if it is not a
               // constant expression
               expression.generateCode(currentScope, false);
             }
             return;
           }
           if ((assignConstant != Constant.NotAConstant)
               && (assignConstant.typeID() != TypeIds.T_float)
               // only for integral types
               && (assignConstant.typeID()
                   != TypeIds.T_double)) { // TODO (philippe) is this test needed ?
             switch (operator) {
               case PLUS:
                 int increment = assignConstant.intValue();
                 if (increment != (short) increment) break; // not representable as a 16-bits value
                 return;
               case MINUS:
                 increment = -assignConstant.intValue();
                 if (increment != (short) increment) break; // not representable as a 16-bits value
                 return;
             }
           }
           // $FALL-THROUGH$
         default:
           if (localBinding.resolvedPosition == -1) {
             assignConstant = expression.constant;
             if (valueRequired) {
               /*
                * restart code gen because we either:
                * - need the value
                * - the constant can have potential side-effect
                */
               localBinding.useFlag = LocalVariableBinding.USED;
               throw new AbortMethod(null, null);
             } else if (assignConstant == Constant.NotAConstant) {
               // we only need to generate the value of the expression's constant if it is not a
               // constant expression
               expression.generateCode(currentScope, false);
             }
             return;
           }
       }
   }
   switch ((this.implicitConversion & TypeIds.IMPLICIT_CONVERSION_MASK) >> 4) {
     case T_JavaLangString:
     case T_JavaLangObject:
     case T_undefined:
       // we enter here if the single name reference is a field of type java.lang.String or if the
       // type of the
       // operation is java.lang.Object
       // For example: o = o + ""; // where the compiled type of o is java.lang.Object.
       // no need for generic cast on previous #getfield since using Object string buffer methods.
       break;
     default:
       // promote the array reference to the suitable operation type
       // generate the increment value (will by itself  be promoted to the operation value)
       if (expression != IntLiteral.One) { // prefix operation
         expression.generateCode(currentScope, true);
       }
   }
   // store the result back into the variable
   switch (this.bits & ASTNode.RestrictiveFlagMASK) {
     case Binding.FIELD: // assigning to a field
       FieldBinding codegenField = ((FieldBinding) this.binding).original();
       fieldStore(
           currentScope,
           codegenField,
           writeAccessor,
           this.actualReceiverType,
           true /* implicit this*/,
           valueRequired);
       // no need for generic cast as value got dupped
       return;
     case Binding.LOCAL: // assigning to a local variable
       LocalVariableBinding localBinding = (LocalVariableBinding) this.binding;
       if (valueRequired) {
         switch (localBinding.type.id) {
           case TypeIds.T_long:
           case TypeIds.T_double:
             break;
           default:
             break;
         }
       }
   }
 }