@Override
  public TypeBinding resolveType(BlockScope scope) {
    boolean expressionIsCast;
    if ((expressionIsCast = this.expression instanceof CastExpression) == true) {
      this.expression.bits |= DisableUnnecessaryCastCheck; // will check later on
    }
    TypeBinding expressionType = this.expression.resolveType(scope);
    if (expressionType == null) {
      this.constant = Constant.NotAConstant;
      return null;
    }
    int expressionTypeID = expressionType.id;
    // autoboxing support
    boolean use15specifics = scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5;
    if (use15specifics) {
      if (!expressionType.isBaseType()) {
        expressionTypeID = scope.environment().computeBoxingType(expressionType).id;
      }
    }
    if (expressionTypeID > 15) {
      this.constant = Constant.NotAConstant;
      scope.problemReporter().invalidOperator(this, expressionType);
      return null;
    }

    int tableId;
    switch ((this.bits & OperatorMASK) >> OperatorSHIFT) {
      case NOT:
        tableId = AND_AND;
        break;
      case TWIDDLE:
        tableId = LEFT_SHIFT;
        break;
      default:
        tableId = MINUS;
    } // + and - cases

    // the code is an int
    // (cast)  left   Op (cast)  rigth --> result
    //  0000   0000       0000   0000      0000
    //  <<16   <<12       <<8    <<4       <<0
    int operatorSignature = OperatorSignatures[tableId][(expressionTypeID << 4) + expressionTypeID];
    this.expression.computeConversion(
        scope,
        TypeBinding.wellKnownType(scope, (operatorSignature >>> 16) & 0x0000F),
        expressionType);
    this.bits |= operatorSignature & 0xF;
    switch (operatorSignature & 0xF) { // only switch on possible result type.....
      case T_boolean:
        this.resolvedType = TypeBinding.BOOLEAN;
        break;
      case T_byte:
        this.resolvedType = TypeBinding.BYTE;
        break;
      case T_char:
        this.resolvedType = TypeBinding.CHAR;
        break;
      case T_double:
        this.resolvedType = TypeBinding.DOUBLE;
        break;
      case T_float:
        this.resolvedType = TypeBinding.FLOAT;
        break;
      case T_int:
        this.resolvedType = TypeBinding.INT;
        break;
      case T_long:
        this.resolvedType = TypeBinding.LONG;
        break;
      default: // error........
        this.constant = Constant.NotAConstant;
        if (expressionTypeID != T_undefined) {
          scope.problemReporter().invalidOperator(this, expressionType);
        }
        return null;
    }
    // compute the constant when valid
    if (this.expression.constant != Constant.NotAConstant) {
      this.constant =
          Constant.computeConstantOperation(
              this.expression.constant,
              expressionTypeID,
              (this.bits & OperatorMASK) >> OperatorSHIFT);
    } else {
      this.constant = Constant.NotAConstant;
      if (((this.bits & OperatorMASK) >> OperatorSHIFT) == NOT) {
        Constant cst = this.expression.optimizedBooleanConstant();
        if (cst != Constant.NotAConstant) {
          this.optimizedBooleanConstant = BooleanConstant.fromValue(!cst.booleanValue());
        }
      }
    }
    if (expressionIsCast) {
      // check need for operand cast
      CastExpression.checkNeedForArgumentCast(
          scope, tableId, operatorSignature, this.expression, expressionTypeID);
    }
    return this.resolvedType;
  }
 /*
  * 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;
         }
       }
   }
 }