*******************************************************************************/
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.*;
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) {
}
}
}
+ 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);
-}
}