import eclipse 3.1 M4 compiler
[org.ibex.tool.git] / src / org / eclipse / jdt / internal / compiler / ast / EqualExpression.java
index 0caeb81..4b2fec9 100644 (file)
@@ -10,7 +10,6 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.compiler.ast;
 
-import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.internal.compiler.ASTVisitor;
 import org.eclipse.jdt.internal.compiler.impl.*;
 import org.eclipse.jdt.internal.compiler.codegen.*;
@@ -19,386 +18,313 @@ import org.eclipse.jdt.internal.compiler.lookup.*;
 
 public class EqualExpression extends BinaryExpression {
 
-public EqualExpression(Expression left, Expression right,int operator) {
-       super(left,right,operator);
-}
-public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
-       if (((bits & OperatorMASK) >> OperatorSHIFT) == EQUAL_EQUAL) {
-               if ((left.constant != NotAConstant) && (left.constant.typeID() == T_boolean)) {
-                       if (left.constant.booleanValue()) { //  true == anything
-                               //  this is equivalent to the right argument inits 
-                               return right.analyseCode(currentScope, flowContext, flowInfo);
-                       } else { // false == anything
-                               //  this is equivalent to the right argument inits negated
-                               return right.analyseCode(currentScope, flowContext, flowInfo).asNegatedCondition();
-                       }
-               }
-               if ((right.constant != NotAConstant) && (right.constant.typeID() == T_boolean)) {
-                       if (right.constant.booleanValue()) { //  anything == true
-                               //  this is equivalent to the right argument inits 
-                               return left.analyseCode(currentScope, flowContext, flowInfo);
-                       } else { // anything == false
-                               //  this is equivalent to the right argument inits negated
-                               return left.analyseCode(currentScope, flowContext, flowInfo).asNegatedCondition();
-                       }
-               }
-               return right.analyseCode(
-                       currentScope, flowContext, 
-                       left.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits()).unconditionalInits();
-       } else { //NOT_EQUAL :
-               if ((left.constant != NotAConstant) && (left.constant.typeID() == T_boolean)) {
-                       if (!left.constant.booleanValue()) { //  false != anything
-                               //  this is equivalent to the right argument inits 
-                               return right.analyseCode(currentScope, flowContext, flowInfo);
-                       } else { // true != anything
-                               //  this is equivalent to the right argument inits negated
-                               return right.analyseCode(currentScope, flowContext, flowInfo).asNegatedCondition();
-                       }
-               }
-               if ((right.constant != NotAConstant) && (right.constant.typeID() == T_boolean)) {
-                       if (!right.constant.booleanValue()) { //  anything != false
-                               //  this is equivalent to the right argument inits 
-                               return left.analyseCode(currentScope, flowContext, flowInfo);
-                       } else { // anything != true
-                               //  this is equivalent to the right argument inits negated
-                               return left.analyseCode(currentScope, flowContext, flowInfo).asNegatedCondition();
-                       }
-               }
-               return right.analyseCode(
-                       currentScope, flowContext, 
-                       left.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits()).asNegatedCondition().unconditionalInits();
+       public EqualExpression(Expression left, Expression right,int operator) {
+               super(left,right,operator);
        }
-}
-public final boolean areTypesCastCompatible(BlockScope scope, TypeBinding castType, TypeBinding expressionType) {
-       //see specifications 5.5
-       //A more complete version of this method is provided on
-       //CastExpression (it deals with constant and need runtime checkcast)
-
-       if (castType == expressionType) return true;
-
-       //========ARRAY===============
-       if (expressionType.isArrayType()) {
-               if (castType.isArrayType()) { //------- (castTb.isArray) expressionTb.isArray -----------
-                       TypeBinding expressionEltType = ((ArrayBinding) expressionType).elementsType(scope);
-                       if (expressionEltType.isBaseType())
-                               // <---stop the recursion------- 
-                               return ((ArrayBinding) castType).elementsType(scope) == expressionEltType;
-                       //recursivly on the elts...
-                       return areTypesCastCompatible(scope, ((ArrayBinding) castType).elementsType(scope), expressionEltType);
+       public void checkNullComparison(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo, FlowInfo initsWhenTrue, FlowInfo initsWhenFalse) {
+               
+               LocalVariableBinding local = this.left.localVariableBinding();
+               if (local != null) {
+                       checkVariableComparison(scope, flowContext, flowInfo, initsWhenTrue, initsWhenFalse, local, right.nullStatus(flowInfo), this.left);
                }
-               if (castType.isBaseType()) {
-                       return false;
+               local = this.right.localVariableBinding();
+               if (local != null) {
+                       checkVariableComparison(scope, flowContext, flowInfo, initsWhenTrue, initsWhenFalse, local, left.nullStatus(flowInfo), this.right);
                }
-               if (castType.isClass()) { //------(castTb.isClass) expressionTb.isArray --------------- 
-                       if (castType.id == T_Object)
-                               return true;
-                       return false;
-               }
-               if (castType.isInterface()) { //------- (castTb.isInterface) expressionTb.isArray -----------
-                       if (castType.id == T_JavaLangCloneable || castType.id == T_JavaIoSerializable) {
-                               return true;
-                       }
-                       return false;
-               }
-
-               return false;
        }
-
-       //------------(castType) null--------------
-       if (expressionType == NullBinding) {
-               return !castType.isBaseType();
-       }
-
-       //========BASETYPE==============
-       if (expressionType.isBaseType()) {
-               return false;
+       private void checkVariableComparison(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo, FlowInfo initsWhenTrue, FlowInfo initsWhenFalse, LocalVariableBinding local, int nullStatus, Expression reference) {
+               switch (nullStatus) {
+                       case FlowInfo.NULL :
+                               flowContext.recordUsingNullReference(scope, local, reference, FlowInfo.NULL, flowInfo);
+                               if (((this.bits & OperatorMASK) >> OperatorSHIFT) == EQUAL_EQUAL) {
+                                       initsWhenTrue.markAsDefinitelyNull(local); // from thereon it is set
+                                       initsWhenFalse.markAsDefinitelyNonNull(local); // from thereon it is set
+                               } else {
+                                       initsWhenTrue.markAsDefinitelyNonNull(local); // from thereon it is set
+                                       initsWhenFalse.markAsDefinitelyNull(local); // from thereon it is set
+                               }
+                               break;
+                       case FlowInfo.NON_NULL :
+                               flowContext.recordUsingNullReference(scope, local, reference, FlowInfo.NON_NULL, flowInfo);
+                               if (((this.bits & OperatorMASK) >> OperatorSHIFT) == EQUAL_EQUAL) {
+                                       initsWhenTrue.markAsDefinitelyNonNull(local); // from thereon it is set
+                               }
+                               break;
+               }       
        }
-
-
-       //========REFERENCE TYPE===================
-
-       if (expressionType.isClass()) {
-               if (castType.isArrayType()) { // ---- (castTb.isArray) expressionTb.isClass -------
-                       if (expressionType.id == T_Object)
-                               return true;
-               }
-               if (castType.isBaseType()) {
-                       return false;
-               }
-               if (castType.isClass()) { // ----- (castTb.isClass) expressionTb.isClass ------ 
-                       if (expressionType.isCompatibleWith(castType))
-                               return true;
-                       else {
-                               if (castType.isCompatibleWith(expressionType)) {
-                                       return true;
+       
+       public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
+               if (((bits & OperatorMASK) >> OperatorSHIFT) == EQUAL_EQUAL) {
+                       if ((left.constant != NotAConstant) && (left.constant.typeID() == T_boolean)) {
+                               if (left.constant.booleanValue()) { //  true == anything
+                                       //  this is equivalent to the right argument inits 
+                                       return right.analyseCode(currentScope, flowContext, flowInfo);
+                               } else { // false == anything
+                                       //  this is equivalent to the right argument inits negated
+                                       return right.analyseCode(currentScope, flowContext, flowInfo).asNegatedCondition();
                                }
-                               return false;
-                       }
-               }
-               if (castType.isInterface()) { // ----- (castTb.isInterface) expressionTb.isClass -------  
-                       if (expressionType.isCompatibleWith(castType))
-                               return true;                
-                       if (!((ReferenceBinding) expressionType).isFinal()) {
-                               return true;
                        }
-                       //no subclass for expressionTb, thus compile-time check is valid                        
-               }
-
-               return false;
-       }
-       if (expressionType.isInterface()) {
-               if (castType.isArrayType()) { // ----- (castTb.isArray) expressionTb.isInterface ------
-                       if (expressionType.id == T_JavaLangCloneable || expressionType.id == T_JavaIoSerializable)
-                               //potential runtime error
-                               {
-                               return true;
+                       if ((right.constant != NotAConstant) && (right.constant.typeID() == T_boolean)) {
+                               if (right.constant.booleanValue()) { //  anything == true
+                                       //  this is equivalent to the right argument inits 
+                                       return left.analyseCode(currentScope, flowContext, flowInfo);
+                               } else { // anything == false
+                                       //  this is equivalent to the right argument inits negated
+                                       return left.analyseCode(currentScope, flowContext, flowInfo).asNegatedCondition();
+                               }
                        }
-                       return false;
-               }
-               if (castType.isBaseType()) {
-                       return false;
-               }
-               if (castType.isClass()) { // ----- (castTb.isClass) expressionTb.isInterface --------
-                       if (castType.id == T_Object)
-                               return true;
-                       if (((ReferenceBinding) castType).isFinal()) { //no subclass for castTb, thus compile-time check is valid
-                               if (castType.isCompatibleWith(expressionType)) {
-                                       return true;
+                       return right.analyseCode(
+                               currentScope, flowContext, 
+                               left.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits()).unconditionalInits();
+               } else { //NOT_EQUAL :
+                       if ((left.constant != NotAConstant) && (left.constant.typeID() == T_boolean)) {
+                               if (!left.constant.booleanValue()) { //  false != anything
+                                       //  this is equivalent to the right argument inits 
+                                       return right.analyseCode(currentScope, flowContext, flowInfo);
+                               } else { // true != anything
+                                       //  this is equivalent to the right argument inits negated
+                                       return right.analyseCode(currentScope, flowContext, flowInfo).asNegatedCondition();
                                }
-                               return false;
                        }
-                       return true;
-               }
-               if (castType.isInterface()) { // ----- (castTb.isInterface) expressionTb.isInterface -------
-                       if (expressionType.isCompatibleWith(castType))
-                               return true;
-                       if (!castType.isCompatibleWith(expressionType)) {
-                               MethodBinding[] castTbMethods = ((ReferenceBinding) castType).methods();
-                               int castTbMethodsLength = castTbMethods.length;
-                               MethodBinding[] expressionTbMethods = ((ReferenceBinding) expressionType).methods();
-                               int expressionTbMethodsLength = expressionTbMethods.length;
-                               for (int i = 0; i < castTbMethodsLength; i++) {
-                                       for (int j = 0; j < expressionTbMethodsLength; j++) {
-                                               if (CharOperation.equals(castTbMethods[i].selector, expressionTbMethods[j].selector)) {
-                                                       if (castTbMethods[i].returnType != expressionTbMethods[j].returnType) {
-                                                               if (castTbMethods[i].areParametersEqual(expressionTbMethods[j])) {
-                                                                       return false;
-                                                               }
-                                                       }
-                                               }
-                                       }
+                       if ((right.constant != NotAConstant) && (right.constant.typeID() == T_boolean)) {
+                               if (!right.constant.booleanValue()) { //  anything != false
+                                       //  this is equivalent to the right argument inits 
+                                       return left.analyseCode(currentScope, flowContext, flowInfo);
+                               } else { // anything != true
+                                       //  this is equivalent to the right argument inits negated
+                                       return left.analyseCode(currentScope, flowContext, flowInfo).asNegatedCondition();
                                }
                        }
-                       return true;
+                       return right.analyseCode(
+                               currentScope, flowContext, 
+                               left.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits()).asNegatedCondition().unconditionalInits();
                }
-               return false;
-       }
-       return false;
-}
-public final void computeConstant(TypeBinding leftType, TypeBinding rightType) {
-       if ((this.left.constant != NotAConstant) && (this.right.constant != NotAConstant)) {
-               this.constant =
-                       Constant.computeConstantOperationEQUAL_EQUAL(
-                               left.constant,
-                               leftType.id,
-                               EQUAL_EQUAL,
-                               right.constant,
-                               rightType.id);
-               if (((this.bits & OperatorMASK) >> OperatorSHIFT) == NOT_EQUAL)
-                       constant = Constant.fromValue(!constant.booleanValue());
-       } else {
-               this.constant = NotAConstant;
-               // no optimization for null == null
-       }
-}
-/**
- * Normal == or != code generation.
- *
- * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
- * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
- * @param valueRequired boolean
- */
-public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) {
-
-       if (constant != NotAConstant) {
-               int pc = codeStream.position;
-               if (valueRequired) 
-                       codeStream.generateConstant(constant, implicitConversion);
-               codeStream.recordPositionsFrom(pc, this.sourceStart);
-               return;
        }
-       Label falseLabel;
-       bits |= OnlyValueRequiredMASK;
-       generateOptimizedBoolean(
-               currentScope, 
-               codeStream, 
-               null, 
-               falseLabel = new Label(codeStream), 
-               valueRequired);
-       if (falseLabel.hasForwardReferences()) {
-               if (valueRequired){
-                       // comparison is TRUE 
-                       codeStream.iconst_1();
-                       if ((bits & ValueForReturnMASK) != 0){
-                               codeStream.ireturn();
-                               // comparison is FALSE
-                               falseLabel.place();
-                               codeStream.iconst_0();
-                       } else {
-                               Label endLabel = new Label(codeStream);
-                               codeStream.goto_(endLabel);
-                               codeStream.decrStackSize(1);
-                               // comparison is FALSE
-                               falseLabel.place();
-                               codeStream.iconst_0();
-                               endLabel.place();
-                       }
+       
+       public final void computeConstant(TypeBinding leftType, TypeBinding rightType) {
+               if ((this.left.constant != NotAConstant) && (this.right.constant != NotAConstant)) {
+                       this.constant =
+                               Constant.computeConstantOperationEQUAL_EQUAL(
+                                       left.constant,
+                                       leftType.id,
+                                       right.constant,
+                                       rightType.id);
+                       if (((this.bits & OperatorMASK) >> OperatorSHIFT) == NOT_EQUAL)
+                               constant = Constant.fromValue(!constant.booleanValue());
                } else {
-                       falseLabel.place();
-               }       
-       }
-}
-/**
- * Boolean operator code generation
- *     Optimized operations are: == and !=
- */
-public void generateOptimizedBoolean(BlockScope currentScope, CodeStream codeStream, Label trueLabel, Label falseLabel, boolean valueRequired) {
-
-       if (constant != Constant.NotAConstant) {
-               super.generateOptimizedBoolean(currentScope, codeStream, trueLabel, falseLabel, valueRequired);
-               return;
+                       this.constant = NotAConstant;
+                       // no optimization for null == null
+               }
        }
-       if (((bits & OperatorMASK) >> OperatorSHIFT) == EQUAL_EQUAL) {
-               if ((left.implicitConversion & 0xF) /*compile-time*/ == T_boolean) {
-                       generateOptimizedBooleanEqual(currentScope, codeStream, trueLabel, falseLabel, valueRequired);
-               } else {
-                       generateOptimizedNonBooleanEqual(currentScope, codeStream, trueLabel, falseLabel, valueRequired);
+       /**
+        * Normal == or != code generation.
+        *
+        * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
+        * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
+        * @param valueRequired boolean
+        */
+       public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) {
+       
+               if (constant != NotAConstant) {
+                       int pc = codeStream.position;
+                       if (valueRequired) 
+                               codeStream.generateConstant(constant, implicitConversion);
+                       codeStream.recordPositionsFrom(pc, this.sourceStart);
+                       return;
                }
-       } else {
-               if ((left.implicitConversion & 0xF) /*compile-time*/ == T_boolean) {
-                       generateOptimizedBooleanEqual(currentScope, codeStream, falseLabel, trueLabel, valueRequired);
-               } else {
-                       generateOptimizedNonBooleanEqual(currentScope, codeStream, falseLabel, trueLabel, valueRequired);
+               Label falseLabel;
+               bits |= OnlyValueRequiredMASK;
+               generateOptimizedBoolean(
+                       currentScope, 
+                       codeStream, 
+                       null, 
+                       falseLabel = new Label(codeStream), 
+                       valueRequired);
+               if (falseLabel.hasForwardReferences()) {
+                       if (valueRequired){
+                               // comparison is TRUE 
+                               codeStream.iconst_1();
+                               if ((bits & ValueForReturnMASK) != 0){
+                                       codeStream.ireturn();
+                                       // comparison is FALSE
+                                       falseLabel.place();
+                                       codeStream.iconst_0();
+                               } else {
+                                       Label endLabel = new Label(codeStream);
+                                       codeStream.goto_(endLabel);
+                                       codeStream.decrStackSize(1);
+                                       // comparison is FALSE
+                                       falseLabel.place();
+                                       codeStream.iconst_0();
+                                       endLabel.place();
+                               }
+                               codeStream.generateImplicitConversion(implicitConversion);
+                       } else {
+                               falseLabel.place();
+                       }       
                }
        }
-}
-/**
- * Boolean generation for == with boolean operands
- *
- * Note this code does not optimize conditional constants !!!!
- */
-public void generateOptimizedBooleanEqual(BlockScope currentScope, CodeStream codeStream, Label trueLabel, Label falseLabel, boolean valueRequired) {
-
-       // optimized cases: true == x, false == x
-       if (left.constant != NotAConstant) {
-               boolean inline = left.constant.booleanValue();
-               right.generateOptimizedBoolean(currentScope, codeStream, (inline ? trueLabel : falseLabel), (inline ? falseLabel : trueLabel), valueRequired);
-               return;
-       } // optimized cases: x == true, x == false
-       if (right.constant != NotAConstant) {
-               boolean inline = right.constant.booleanValue();
-               left.generateOptimizedBoolean(currentScope, codeStream, (inline ? trueLabel : falseLabel), (inline ? falseLabel : trueLabel), valueRequired);
-               return;
-       }
-       // default case
-       left.generateCode(currentScope, codeStream, valueRequired);
-       right.generateCode(currentScope, codeStream, valueRequired);
-       if (valueRequired) {
-               if (falseLabel == null) {
-                       if (trueLabel != null) {
-                               // implicit falling through the FALSE case
-                               codeStream.if_icmpeq(trueLabel);
+       /**
+        * Boolean operator code generation
+        *      Optimized operations are: == and !=
+        */
+       public void generateOptimizedBoolean(BlockScope currentScope, CodeStream codeStream, Label trueLabel, Label falseLabel, boolean valueRequired) {
+       
+               if (constant != Constant.NotAConstant) {
+                       super.generateOptimizedBoolean(currentScope, codeStream, trueLabel, falseLabel, valueRequired);
+                       return;
+               }
+               if (((bits & OperatorMASK) >> OperatorSHIFT) == EQUAL_EQUAL) {
+                       if ((left.implicitConversion & COMPILE_TYPE_MASK) /*compile-time*/ == T_boolean) {
+                               generateOptimizedBooleanEqual(currentScope, codeStream, trueLabel, falseLabel, valueRequired);
+                       } else {
+                               generateOptimizedNonBooleanEqual(currentScope, codeStream, trueLabel, falseLabel, valueRequired);
                        }
                } else {
-                       // implicit falling through the TRUE case
-                       if (trueLabel == null) {
-                               codeStream.if_icmpne(falseLabel);
+                       if ((left.implicitConversion & COMPILE_TYPE_MASK) /*compile-time*/ == T_boolean) {
+                               generateOptimizedBooleanEqual(currentScope, codeStream, falseLabel, trueLabel, valueRequired);
                        } else {
-                               // no implicit fall through TRUE/FALSE --> should never occur
+                               generateOptimizedNonBooleanEqual(currentScope, codeStream, falseLabel, trueLabel, valueRequired);
                        }
                }
        }
-       // reposition the endPC
-       codeStream.updateLastRecordedEndPC(codeStream.position);                                        
-}
-/**
- * Boolean generation for == with non-boolean operands
- *
- */
-public void generateOptimizedNonBooleanEqual(BlockScope currentScope, CodeStream codeStream, Label trueLabel, Label falseLabel, boolean valueRequired) {
-
-       int pc = codeStream.position;
-       Constant inline;
-       if ((inline = right.constant) != NotAConstant) {
-               // optimized case: x == 0
-               if (((left.implicitConversion >> 4) == T_int) && (inline.intValue() == 0)) {
-                       left.generateCode(currentScope, codeStream, valueRequired);
-                       if (valueRequired) {
-                               if (falseLabel == null) {
-                                       if (trueLabel != null) {
-                                               // implicit falling through the FALSE case
-                                               codeStream.ifeq(trueLabel);
-                                       }
+       /**
+        * Boolean generation for == with boolean operands
+        *
+        * Note this code does not optimize conditional constants !!!!
+        */
+       public void generateOptimizedBooleanEqual(BlockScope currentScope, CodeStream codeStream, Label trueLabel, Label falseLabel, boolean valueRequired) {
+       
+               // optimized cases: true == x, false == x
+               if (left.constant != NotAConstant) {
+                       boolean inline = left.constant.booleanValue();
+                       right.generateOptimizedBoolean(currentScope, codeStream, (inline ? trueLabel : falseLabel), (inline ? falseLabel : trueLabel), valueRequired);
+                       return;
+               } // optimized cases: x == true, x == false
+               if (right.constant != NotAConstant) {
+                       boolean inline = right.constant.booleanValue();
+                       left.generateOptimizedBoolean(currentScope, codeStream, (inline ? trueLabel : falseLabel), (inline ? falseLabel : trueLabel), valueRequired);
+                       return;
+               }
+               // default case
+               left.generateCode(currentScope, codeStream, valueRequired);
+               right.generateCode(currentScope, codeStream, valueRequired);
+               if (valueRequired) {
+                       if (falseLabel == null) {
+                               if (trueLabel != null) {
+                                       // implicit falling through the FALSE case
+                                       codeStream.if_icmpeq(trueLabel);
+                               }
+                       } else {
+                               // implicit falling through the TRUE case
+                               if (trueLabel == null) {
+                                       codeStream.if_icmpne(falseLabel);
                                } else {
-                                       // implicit falling through the TRUE case
-                                       if (trueLabel == null) {
-                                               codeStream.ifne(falseLabel);
-                                       } else {
-                                               // no implicit fall through TRUE/FALSE --> should never occur
-                                       }
+                                       // no implicit fall through TRUE/FALSE --> should never occur
                                }
                        }
-                       codeStream.recordPositionsFrom(pc, this.sourceStart);
-                       return;
                }
+               // reposition the endPC
+               codeStream.updateLastRecordedEndPC(codeStream.position);                                        
        }
-       if ((inline = left.constant) != NotAConstant) {
-               // optimized case: 0 == x
-               if (((left.implicitConversion >> 4) == T_int)
-                       && (inline.intValue() == 0)) {
-                       right.generateCode(currentScope, codeStream, valueRequired);
-                       if (valueRequired) {
-                               if (falseLabel == null) {
-                                       if (trueLabel != null) {
-                                               // implicit falling through the FALSE case
-                                               codeStream.ifeq(trueLabel);
+       /**
+        * Boolean generation for == with non-boolean operands
+        *
+        */
+       public void generateOptimizedNonBooleanEqual(BlockScope currentScope, CodeStream codeStream, Label trueLabel, Label falseLabel, boolean valueRequired) {
+       
+               int pc = codeStream.position;
+               Constant inline;
+               if ((inline = right.constant) != NotAConstant) {
+                       // optimized case: x == 0
+                       if ((((left.implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4) == T_int) && (inline.intValue() == 0)) {
+                               left.generateCode(currentScope, codeStream, valueRequired);
+                               if (valueRequired) {
+                                       if (falseLabel == null) {
+                                               if (trueLabel != null) {
+                                                       // implicit falling through the FALSE case
+                                                       codeStream.ifeq(trueLabel);
+                                               }
+                                       } else {
+                                               // implicit falling through the TRUE case
+                                               if (trueLabel == null) {
+                                                       codeStream.ifne(falseLabel);
+                                               } else {
+                                                       // no implicit fall through TRUE/FALSE --> should never occur
+                                               }
                                        }
-                               } else {
-                                       // implicit falling through the TRUE case
-                                       if (trueLabel == null) {
-                                               codeStream.ifne(falseLabel);
+                               }
+                               codeStream.recordPositionsFrom(pc, this.sourceStart);
+                               return;
+                       }
+               }
+               if ((inline = left.constant) != NotAConstant) {
+                       // optimized case: 0 == x
+                       if ((((left.implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4) == T_int)
+                               && (inline.intValue() == 0)) {
+                               right.generateCode(currentScope, codeStream, valueRequired);
+                               if (valueRequired) {
+                                       if (falseLabel == null) {
+                                               if (trueLabel != null) {
+                                                       // implicit falling through the FALSE case
+                                                       codeStream.ifeq(trueLabel);
+                                               }
                                        } else {
-                                               // no implicit fall through TRUE/FALSE --> should never occur
+                                               // implicit falling through the TRUE case
+                                               if (trueLabel == null) {
+                                                       codeStream.ifne(falseLabel);
+                                               } else {
+                                                       // no implicit fall through TRUE/FALSE --> should never occur
+                                               }
                                        }
                                }
+                               codeStream.recordPositionsFrom(pc, this.sourceStart);
+                               return;
                        }
-                       codeStream.recordPositionsFrom(pc, this.sourceStart);
-                       return;
                }
-       }
-       // null cases
-       // optimized case: x == null
-       if (right instanceof NullLiteral) {
-               if (left instanceof NullLiteral) {
-                       // null == null
-                       if (valueRequired) {
-                                       if ((bits & OnlyValueRequiredMASK) != 0) {
-                                               if (((bits & OperatorMASK) >> OperatorSHIFT) == EQUAL_EQUAL) {
-                                                       codeStream.iconst_1();
+               // null cases
+               // optimized case: x == null
+               if (right instanceof NullLiteral) {
+                       if (left instanceof NullLiteral) {
+                               // null == null
+                               if (valueRequired) {
+                                               if ((bits & OnlyValueRequiredMASK) != 0) {
+                                                       if (((bits & OperatorMASK) >> OperatorSHIFT) == EQUAL_EQUAL) {
+                                                               codeStream.iconst_1();
+                                                       } else {
+                                                               codeStream.iconst_0();
+                                                       }
                                                } else {
-                                                       codeStream.iconst_0();
+                                                       if (falseLabel == null) {
+                                                               // implicit falling through the FALSE case
+                                                               if (trueLabel != null) {
+                                                                       codeStream.goto_(trueLabel);
+                                                               }
+                                                       }
+                                       }
+                               }
+                       } else {
+                               left.generateCode(currentScope, codeStream, valueRequired);
+                               if (valueRequired) {
+                                       if (falseLabel == null) {
+                                               if (trueLabel != null) {
+                                                       // implicit falling through the FALSE case
+                                                       codeStream.ifnull(trueLabel);
                                                }
                                        } else {
-                                               if (falseLabel == null) {
-                                                       // implicit falling through the FALSE case
-                                                       if (trueLabel != null) {
-                                                               codeStream.goto_(trueLabel);
-                                                       }
+                                               // implicit falling through the TRUE case
+                                               if (trueLabel == null) {
+                                                       codeStream.ifnonnull(falseLabel);
+                                               } else {
+                                                       // no implicit fall through TRUE/FALSE --> should never occur
                                                }
+                                       }
                                }
                        }
-               } else {
-                       left.generateCode(currentScope, codeStream, valueRequired);
+                       codeStream.recordPositionsFrom(pc, this.sourceStart);
+                       return;
+               } else if (left instanceof NullLiteral) { // optimized case: null == x
+                       right.generateCode(currentScope, codeStream, valueRequired);
                        if (valueRequired) {
                                if (falseLabel == null) {
                                        if (trueLabel != null) {
@@ -414,165 +340,162 @@ public void generateOptimizedNonBooleanEqual(BlockScope currentScope, CodeStream
                                        }
                                }
                        }
+                       codeStream.recordPositionsFrom(pc, this.sourceStart);
+                       return;
                }
-               codeStream.recordPositionsFrom(pc, this.sourceStart);
-               return;
-       } else if (left instanceof NullLiteral) { // optimized case: null == x
+       
+               // default case
+               left.generateCode(currentScope, codeStream, valueRequired);
                right.generateCode(currentScope, codeStream, valueRequired);
                if (valueRequired) {
                        if (falseLabel == null) {
                                if (trueLabel != null) {
                                        // implicit falling through the FALSE case
-                                       codeStream.ifnull(trueLabel);
+                                       switch ((left.implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4) { // operand runtime type
+                                               case T_int :
+                                                       codeStream.if_icmpeq(trueLabel);
+                                                       break;
+                                               case T_float :
+                                                       codeStream.fcmpl();
+                                                       codeStream.ifeq(trueLabel);
+                                                       break;
+                                               case T_long :
+                                                       codeStream.lcmp();
+                                                       codeStream.ifeq(trueLabel);
+                                                       break;
+                                               case T_double :
+                                                       codeStream.dcmpl();
+                                                       codeStream.ifeq(trueLabel);
+                                                       break;
+                                               default :
+                                                       codeStream.if_acmpeq(trueLabel);
+                                       }
                                }
                        } else {
                                // implicit falling through the TRUE case
                                if (trueLabel == null) {
-                                       codeStream.ifnonnull(falseLabel);
+                                       switch ((left.implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4) { // operand runtime type
+                                               case T_int :
+                                                       codeStream.if_icmpne(falseLabel);
+                                                       break;
+                                               case T_float :
+                                                       codeStream.fcmpl();
+                                                       codeStream.ifne(falseLabel);
+                                                       break;
+                                               case T_long :
+                                                       codeStream.lcmp();
+                                                       codeStream.ifne(falseLabel);
+                                                       break;
+                                               case T_double :
+                                                       codeStream.dcmpl();
+                                                       codeStream.ifne(falseLabel);
+                                                       break;
+                                               default :
+                                                       codeStream.if_acmpne(falseLabel);
+                                       }
                                } else {
                                        // no implicit fall through TRUE/FALSE --> should never occur
                                }
                        }
                }
                codeStream.recordPositionsFrom(pc, this.sourceStart);
-               return;
        }
-
-       // default case
-       left.generateCode(currentScope, codeStream, valueRequired);
-       right.generateCode(currentScope, codeStream, valueRequired);
-       if (valueRequired) {
-               if (falseLabel == null) {
-                       if (trueLabel != null) {
-                               // implicit falling through the FALSE case
-                               switch (left.implicitConversion >> 4) { // operand runtime type
-                                       case T_int :
-                                               codeStream.if_icmpeq(trueLabel);
-                                               break;
-                                       case T_float :
-                                               codeStream.fcmpl();
-                                               codeStream.ifeq(trueLabel);
-                                               break;
-                                       case T_long :
-                                               codeStream.lcmp();
-                                               codeStream.ifeq(trueLabel);
-                                               break;
-                                       case T_double :
-                                               codeStream.dcmpl();
-                                               codeStream.ifeq(trueLabel);
-                                               break;
-                                       default :
-                                               codeStream.if_acmpeq(trueLabel);
-                               }
-                       }
-               } else {
-                       // implicit falling through the TRUE case
-                       if (trueLabel == null) {
-                               switch (left.implicitConversion >> 4) { // operand runtime type
-                                       case T_int :
-                                               codeStream.if_icmpne(falseLabel);
-                                               break;
-                                       case T_float :
-                                               codeStream.fcmpl();
-                                               codeStream.ifne(falseLabel);
-                                               break;
-                                       case T_long :
-                                               codeStream.lcmp();
-                                               codeStream.ifne(falseLabel);
-                                               break;
-                                       case T_double :
-                                               codeStream.dcmpl();
-                                               codeStream.ifne(falseLabel);
-                                               break;
-                                       default :
-                                               codeStream.if_acmpne(falseLabel);
-                               }
-                       } else {
-                               // no implicit fall through TRUE/FALSE --> should never occur
-                       }
-               }
-       }
-       codeStream.recordPositionsFrom(pc, this.sourceStart);
-}
-public boolean isCompactableOperation() {
-       return false;
-}
-public TypeBinding resolveType(BlockScope scope) {
-
-               boolean leftIsCast, rightIsCast;
-               if ((leftIsCast = left instanceof CastExpression) == true) left.bits |= IgnoreNeedForCastCheckMASK; // will check later on
-               TypeBinding leftType = left.resolveType(scope);
-
-               if ((rightIsCast = right instanceof CastExpression) == true) right.bits |= IgnoreNeedForCastCheckMASK; // will check later on
-               TypeBinding rightType = right.resolveType(scope);
-
-       // always return BooleanBinding
-       if (leftType == null || rightType == null){
-               constant = NotAConstant;                
-               return null;
+       public boolean isCompactableOperation() {
+               return false;
        }
-
-       // both base type
-       if (leftType.isBaseType() && rightType.isBaseType()) {
-               // the code is an int
-               // (cast)  left   == (cast)  right --> result
-               //  0000   0000       0000   0000      0000
-               //  <<16   <<12       <<8    <<4       <<0
-               int operatorSignature = OperatorSignatures[EQUAL_EQUAL][ (leftType.id << 4) + rightType.id];
-               left.implicitConversion = operatorSignature >>> 12;
-               right.implicitConversion = (operatorSignature >>> 4) & 0x000FF;
-               bits |= operatorSignature & 0xF;                
-               if ((operatorSignature & 0x0000F) == T_undefined) {
-                       constant = Constant.NotAConstant;
-                       scope.problemReporter().invalidOperator(this, leftType, rightType);
+       public TypeBinding resolveType(BlockScope scope) {
+       
+                       boolean leftIsCast, rightIsCast;
+                       if ((leftIsCast = left instanceof CastExpression) == true) left.bits |= IgnoreNeedForCastCheckMASK; // will check later on
+                       TypeBinding originalLeftType = left.resolveType(scope);
+       
+                       if ((rightIsCast = right instanceof CastExpression) == true) right.bits |= IgnoreNeedForCastCheckMASK; // will check later on
+                       TypeBinding originalRightType = right.resolveType(scope);
+       
+               // always return BooleanBinding
+               if (originalLeftType == null || originalRightType == null){
+                       constant = NotAConstant;                
                        return null;
                }
-               // check need for operand cast
-               if (leftIsCast || rightIsCast) {
-                       CastExpression.checkNeedForArgumentCasts(scope, EQUAL_EQUAL, operatorSignature, left, leftType.id, leftIsCast, right, rightType.id, rightIsCast);
+       
+               // autoboxing support
+               LookupEnvironment env = scope.environment();
+               boolean use15specifics = env.options.sourceLevel >= JDK1_5;
+               TypeBinding leftType = originalLeftType, rightType = originalRightType;
+               if (use15specifics) {
+                       if (leftType != NullBinding && leftType.isBaseType()) {
+                               if (!rightType.isBaseType()) {
+                                       rightType = env.computeBoxingType(rightType);
+                               }
+                       } else {
+                               if (rightType != NullBinding && rightType.isBaseType()) {
+                                       leftType = env.computeBoxingType(leftType);
+                               }
+                       }
                }
-               computeConstant(leftType, rightType);
-               return this.resolvedType = BooleanBinding;
-       }
-
-       // Object references 
-       // spec 15.20.3
-       if (areTypesCastCompatible(scope, rightType, leftType) || areTypesCastCompatible(scope, leftType, rightType)) {
-               // (special case for String)
-               if ((rightType.id == T_String) && (leftType.id == T_String)) {
+               // both base type
+               if (leftType.isBaseType() && rightType.isBaseType()) {
+                       int leftTypeID = leftType.id;
+                       int rightTypeID = rightType.id;
+       
+                       // the code is an int
+                       // (cast)  left   == (cast)  right --> result
+                       //  0000   0000       0000   0000      0000
+                       //  <<16   <<12       <<8    <<4       <<0
+                       int operatorSignature = OperatorSignatures[EQUAL_EQUAL][ (leftTypeID << 4) + rightTypeID];
+                       left.computeConversion(scope, TypeBinding.wellKnownType(scope, (operatorSignature >>> 16) & 0x0000F), originalLeftType);
+                       right.computeConversion(scope, TypeBinding.wellKnownType(scope, (operatorSignature >>> 8) & 0x0000F), originalRightType);
+                       bits |= operatorSignature & 0xF;                
+                       if ((operatorSignature & 0x0000F) == T_undefined) {
+                               constant = Constant.NotAConstant;
+                               scope.problemReporter().invalidOperator(this, leftType, rightType);
+                               return null;
+                       }
+                       // check need for operand cast
+                       if (leftIsCast || rightIsCast) {
+                               CastExpression.checkNeedForArgumentCasts(scope, EQUAL_EQUAL, operatorSignature, left, leftType.id, leftIsCast, right, rightType.id, rightIsCast);
+                       }
                        computeConstant(leftType, rightType);
-               } else {
-                       constant = NotAConstant;
-               }
-               if (rightType.id == T_String) {
-                       right.implicitConversion = String2String;
-               }
-               if (leftType.id == T_String) {
-                       left.implicitConversion = String2String;
+                       return this.resolvedType = BooleanBinding;
                }
-               // check need for operand cast
-               boolean unnecessaryLeftCast = (left.bits & UnnecessaryCastMask) != 0;
-               boolean unnecessaryRightCast = (right.bits & UnnecessaryCastMask) != 0;
-               if (unnecessaryLeftCast || unnecessaryRightCast) {
-                       TypeBinding alternateLeftType = unnecessaryLeftCast ? ((CastExpression)left).expression.resolvedType : leftType;
-                       TypeBinding alternateRightType = unnecessaryRightCast ? ((CastExpression)right).expression.resolvedType : rightType;
-                       if (areTypesCastCompatible(scope, alternateLeftType, alternateRightType)
-                                       || areTypesCastCompatible(scope, alternateRightType, alternateLeftType)) {
-                               if (unnecessaryLeftCast) scope.problemReporter().unnecessaryCast((CastExpression)left); 
-                               if (unnecessaryRightCast) scope.problemReporter().unnecessaryCast((CastExpression)right);
+       
+               // Object references 
+               // spec 15.20.3
+               if (this.checkCastTypesCompatibility(scope, leftType, rightType, null) 
+                               || this.checkCastTypesCompatibility(scope, rightType, leftType, null)) {
+
+                       // (special case for String)
+                       if ((rightType.id == T_JavaLangString) && (leftType.id == T_JavaLangString)) {
+                               computeConstant(leftType, rightType);
+                       } else {
+                               constant = NotAConstant;
                        }
+                       TypeBinding objectType = scope.getJavaLangObject();
+                       left.computeConversion(scope, objectType, leftType);
+                       right.computeConversion(scope, objectType, rightType);
+                       // check need for operand cast
+                       boolean unnecessaryLeftCast = (left.bits & UnnecessaryCastMask) != 0;
+                       boolean unnecessaryRightCast = (right.bits & UnnecessaryCastMask) != 0;
+                       if (unnecessaryLeftCast || unnecessaryRightCast) {
+                               TypeBinding alternateLeftType = unnecessaryLeftCast ? ((CastExpression)left).expression.resolvedType : leftType;
+                               TypeBinding alternateRightType = unnecessaryRightCast ? ((CastExpression)right).expression.resolvedType : rightType;
+                               if (this.checkCastTypesCompatibility(scope, alternateLeftType, alternateRightType, null) 
+                                               || this.checkCastTypesCompatibility(scope, alternateRightType, alternateLeftType, null)) {
+                                       if (unnecessaryLeftCast) scope.problemReporter().unnecessaryCast((CastExpression)left); 
+                                       if (unnecessaryRightCast) scope.problemReporter().unnecessaryCast((CastExpression)right);
+                               }
+                       }
+                       return this.resolvedType = BooleanBinding;
                }
-               return this.resolvedType = BooleanBinding;
+               constant = NotAConstant;
+               scope.problemReporter().notCompatibleTypesError(this, leftType, rightType);
+               return null;
        }
-       constant = NotAConstant;
-       scope.problemReporter().notCompatibleTypesError(this, leftType, rightType);
-       return null;
-}
-public void traverse(ASTVisitor visitor, BlockScope scope) {
-       if (visitor.visit(this, scope)) {
-               left.traverse(visitor, scope);
-               right.traverse(visitor, scope);
+       public void traverse(ASTVisitor visitor, BlockScope scope) {
+               if (visitor.visit(this, scope)) {
+                       left.traverse(visitor, scope);
+                       right.traverse(visitor, scope);
+               }
+               visitor.endVisit(this, scope);
        }
-       visitor.endVisit(this, scope);
-}
 }