X-Git-Url: http://git.phpeclipse.com diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/ConditionalExpression.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/ConditionalExpression.java index d234618..39b98a3 100644 --- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/ConditionalExpression.java +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/ConditionalExpression.java @@ -1,35 +1,43 @@ /******************************************************************************* - * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * Copyright (c) 2000, 2003 IBM Corporation and others. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Common Public License v0.5 + * are made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v05.html + * http://www.eclipse.org/legal/cpl-v10.html * * Contributors: * IBM Corporation - initial API and implementation - ******************************************************************************/ + *******************************************************************************/ package net.sourceforge.phpdt.internal.compiler.ast; -import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; -import net.sourceforge.phpdt.internal.compiler.impl.*; -import net.sourceforge.phpdt.internal.compiler.codegen.*; -import net.sourceforge.phpdt.internal.compiler.flow.*; -import net.sourceforge.phpdt.internal.compiler.lookup.*; +import net.sourceforge.phpdt.internal.compiler.ASTVisitor; +import net.sourceforge.phpdt.internal.compiler.flow.FlowContext; +import net.sourceforge.phpdt.internal.compiler.flow.FlowInfo; +import net.sourceforge.phpdt.internal.compiler.flow.UnconditionalFlowInfo; +import net.sourceforge.phpdt.internal.compiler.impl.Constant; +import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope; public class ConditionalExpression extends OperatorExpression { public Expression condition, valueIfTrue, valueIfFalse; - private int returnTypeSlotSize = 1; + + public Constant optimizedBooleanConstant; + + public Constant optimizedIfTrueConstant; + + public Constant optimizedIfFalseConstant; + + //private int returnTypeSlotSize = 1; // for local variables table attributes - int thenInitStateIndex = -1; - int elseInitStateIndex = -1; + int trueInitStateIndex = -1; + + int falseInitStateIndex = -1; + int mergedInitStateIndex = -1; - - public ConditionalExpression( - Expression condition, - Expression valueIfTrue, - Expression valueIfFalse) { + + public ConditionalExpression(Expression condition, Expression valueIfTrue, + Expression valueIfFalse) { this.condition = condition; this.valueIfTrue = valueIfTrue; this.valueIfFalse = valueIfFalse; @@ -37,372 +45,429 @@ public class ConditionalExpression extends OperatorExpression { sourceEnd = valueIfFalse.sourceEnd; } - public FlowInfo analyseCode( - BlockScope currentScope, - FlowContext flowContext, - FlowInfo flowInfo) { + public FlowInfo analyseCode(BlockScope currentScope, + FlowContext flowContext, FlowInfo flowInfo) { - Constant conditionConstant = condition.conditionalConstant(); + Constant cst = this.condition.optimizedBooleanConstant(); + boolean isConditionOptimizedTrue = cst != NotAConstant + && cst.booleanValue() == true; + boolean isConditionOptimizedFalse = cst != NotAConstant + && cst.booleanValue() == false; - flowInfo = condition.analyseCode(currentScope, flowContext, flowInfo, conditionConstant == NotAConstant); + int mode = flowInfo.reachMode(); + flowInfo = condition.analyseCode(currentScope, flowContext, flowInfo, + cst == NotAConstant); - if (conditionConstant != NotAConstant) { - if (conditionConstant.booleanValue() == true) { - // TRUE ? left : right - FlowInfo resultInfo = - valueIfTrue.analyseCode(currentScope, flowContext, flowInfo.initsWhenTrue().unconditionalInits()); - // analyse valueIfFalse, but do not take into account any of its infos - valueIfFalse.analyseCode( - currentScope, - flowContext, - flowInfo.initsWhenFalse().copy().unconditionalInits().markAsFakeReachable(true)); - mergedInitStateIndex = - currentScope.methodScope().recordInitializationStates(resultInfo); - return resultInfo; - } else { - // FALSE ? left : right - // analyse valueIfTrue, but do not take into account any of its infos - valueIfTrue.analyseCode( - currentScope, - flowContext, - flowInfo.initsWhenTrue().copy().unconditionalInits().markAsFakeReachable(true)); - FlowInfo mergeInfo = - valueIfFalse.analyseCode(currentScope, flowContext, flowInfo.initsWhenFalse().unconditionalInits()); - mergedInitStateIndex = - currentScope.methodScope().recordInitializationStates(mergeInfo); - return mergeInfo; - } + // process the if-true part + FlowInfo trueFlowInfo = flowInfo.initsWhenTrue().copy(); + if (isConditionOptimizedFalse) { + trueFlowInfo.setReachMode(FlowInfo.UNREACHABLE); } + trueInitStateIndex = currentScope.methodScope() + .recordInitializationStates(trueFlowInfo); + trueFlowInfo = valueIfTrue.analyseCode(currentScope, flowContext, + trueFlowInfo); - // store a copy of the merged info, so as to compute the local variable attributes afterwards - FlowInfo trueInfo = flowInfo.initsWhenTrue(); - thenInitStateIndex = - currentScope.methodScope().recordInitializationStates(trueInfo); - FlowInfo falseInfo = flowInfo.initsWhenFalse(); - elseInitStateIndex = - currentScope.methodScope().recordInitializationStates(falseInfo); - - // propagate analysis - trueInfo = valueIfTrue.analyseCode(currentScope, flowContext, trueInfo.copy()); - falseInfo = - valueIfFalse.analyseCode(currentScope, flowContext, falseInfo.copy()); - - // merge back using a conditional info - 1GK2BLM - // if ((t && (v = t)) ? t : t && (v = f)) r = v; -- ok - FlowInfo mergedInfo = - FlowInfo.conditional( - trueInfo.initsWhenTrue().copy().unconditionalInits().mergedWith( // must copy, since could be shared with trueInfo.initsWhenFalse()... - falseInfo.initsWhenTrue().copy().unconditionalInits()), - trueInfo.initsWhenFalse().unconditionalInits().mergedWith( - falseInfo.initsWhenFalse().unconditionalInits())); - /* - FlowInfo mergedInfo = valueIfTrue.analyseCode( - currentScope, - flowContext, - flowInfo.initsWhenTrue().copy()). - unconditionalInits(). - mergedWith( - valueIfFalse.analyseCode( - currentScope, - flowContext, - flowInfo.initsWhenFalse().copy()). - unconditionalInits()); - */ - mergedInitStateIndex = - currentScope.methodScope().recordInitializationStates(mergedInfo); - return mergedInfo; - } - - /** - * Code generation for the conditional operator ?: - * - * @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) { - - int pc = codeStream.position; - Label endifLabel, falseLabel; - if (constant != NotAConstant) { - if (valueRequired) - codeStream.generateConstant(constant, implicitConversion); - codeStream.recordPositionsFrom(pc, this.sourceStart); - return; + // process the if-false part + FlowInfo falseFlowInfo = flowInfo.initsWhenFalse().copy(); + if (isConditionOptimizedTrue) { + falseFlowInfo.setReachMode(FlowInfo.UNREACHABLE); } - Constant cst = condition.constant; - Constant condCst = condition.conditionalConstant(); - boolean needTruePart = - !(((cst != NotAConstant) && (cst.booleanValue() == false)) - || ((condCst != NotAConstant) && (condCst.booleanValue() == false))); - boolean needFalsePart = - !(((cst != NotAConstant) && (cst.booleanValue() == true)) - || ((condCst != NotAConstant) && (condCst.booleanValue() == true))); - endifLabel = new Label(codeStream); - - // Generate code for the condition - boolean needConditionValue = (cst == NotAConstant) && (condCst == NotAConstant); - condition.generateOptimizedBoolean( - currentScope, - codeStream, - null, - (falseLabel = new Label(codeStream)), - needConditionValue); + falseInitStateIndex = currentScope.methodScope() + .recordInitializationStates(falseFlowInfo); + falseFlowInfo = valueIfFalse.analyseCode(currentScope, flowContext, + falseFlowInfo); - if (thenInitStateIndex != -1) { - codeStream.removeNotDefinitelyAssignedVariables( - currentScope, - thenInitStateIndex); - codeStream.addDefinitelyAssignedVariables(currentScope, thenInitStateIndex); - } - // Then code generation - if (needTruePart) { - valueIfTrue.generateCode(currentScope, codeStream, valueRequired); - if (needFalsePart) { - // Jump over the else part - int position = codeStream.position; - codeStream.goto_(endifLabel); - codeStream.updateLastRecordedEndPC(position); - // Tune codestream stack size - if (valueRequired) { - codeStream.decrStackSize(returnTypeSlotSize); - } - } - } - if (needFalsePart) { - falseLabel.place(); - if (elseInitStateIndex != -1) { - codeStream.removeNotDefinitelyAssignedVariables( - currentScope, - elseInitStateIndex); - codeStream.addDefinitelyAssignedVariables(currentScope, elseInitStateIndex); - } - valueIfFalse.generateCode(currentScope, codeStream, valueRequired); - // End of if statement - endifLabel.place(); - } - // May loose some local variable initializations : affecting the local variable attributes - if (mergedInitStateIndex != -1) { - codeStream.removeNotDefinitelyAssignedVariables( - currentScope, - mergedInitStateIndex); - } - // implicit conversion - if (valueRequired) - codeStream.generateImplicitConversion(implicitConversion); - codeStream.recordPositionsFrom(pc, this.sourceStart); - } + // merge if-true & if-false initializations + FlowInfo mergedInfo; + if (isConditionOptimizedTrue) { + mergedInfo = trueFlowInfo + .addPotentialInitializationsFrom(falseFlowInfo); + } else if (isConditionOptimizedFalse) { + mergedInfo = falseFlowInfo + .addPotentialInitializationsFrom(trueFlowInfo); + } else { + // merge using a conditional info - 1GK2BLM + // if ((t && (v = t)) ? t : t && (v = f)) r = v; -- ok + cst = this.optimizedIfTrueConstant; + boolean isValueIfTrueOptimizedTrue = cst != null + && cst != NotAConstant && cst.booleanValue() == true; + boolean isValueIfTrueOptimizedFalse = cst != null + && cst != NotAConstant && cst.booleanValue() == false; - /** - * Optimized boolean code generation for the conditional operator ?: - */ - public void generateOptimizedBoolean( - BlockScope currentScope, - CodeStream codeStream, - Label trueLabel, - Label falseLabel, - boolean valueRequired) { + cst = this.optimizedIfFalseConstant; + boolean isValueIfFalseOptimizedTrue = cst != null + && cst != NotAConstant && cst.booleanValue() == true; + boolean isValueIfFalseOptimizedFalse = cst != null + && cst != NotAConstant && cst.booleanValue() == false; - if ((constant != Constant.NotAConstant) && (constant.typeID() == T_boolean) // constant - || (valueIfTrue.implicitConversion >> 4) != T_boolean) { // non boolean values - super.generateOptimizedBoolean(currentScope, codeStream, trueLabel, falseLabel, valueRequired); - return; - } - int pc = codeStream.position; - Constant cst = condition.constant; - Constant condCst = condition.conditionalConstant(); - boolean needTruePart = - !(((cst != NotAConstant) && (cst.booleanValue() == false)) - || ((condCst != NotAConstant) && (condCst.booleanValue() == false))); - boolean needFalsePart = - !(((cst != NotAConstant) && (cst.booleanValue() == true)) - || ((condCst != NotAConstant) && (condCst.booleanValue() == true))); + UnconditionalFlowInfo trueInfoWhenTrue = trueFlowInfo + .initsWhenTrue().copy().unconditionalInits(); + if (isValueIfTrueOptimizedFalse) + trueInfoWhenTrue.setReachMode(FlowInfo.UNREACHABLE); - Label internalFalseLabel, endifLabel = new Label(codeStream); + UnconditionalFlowInfo falseInfoWhenTrue = falseFlowInfo + .initsWhenTrue().copy().unconditionalInits(); + if (isValueIfFalseOptimizedFalse) + falseInfoWhenTrue.setReachMode(FlowInfo.UNREACHABLE); - // Generate code for the condition - boolean needConditionValue = (cst == NotAConstant) && (condCst == NotAConstant); - condition.generateOptimizedBoolean( - currentScope, - codeStream, - null, - internalFalseLabel = new Label(codeStream), - needConditionValue); + UnconditionalFlowInfo trueInfoWhenFalse = trueFlowInfo + .initsWhenFalse().copy().unconditionalInits(); + if (isValueIfTrueOptimizedTrue) + trueInfoWhenFalse.setReachMode(FlowInfo.UNREACHABLE); - if (thenInitStateIndex != -1) { - codeStream.removeNotDefinitelyAssignedVariables( - currentScope, - thenInitStateIndex); - codeStream.addDefinitelyAssignedVariables(currentScope, thenInitStateIndex); - } - // Then code generation - if (needTruePart) { - valueIfTrue.generateOptimizedBoolean(currentScope, codeStream, trueLabel, falseLabel, valueRequired); - - if (needFalsePart) { - // Jump over the else part - int position = codeStream.position; - codeStream.goto_(endifLabel); - codeStream.updateLastRecordedEndPC(position); - // Tune codestream stack size - //if (valueRequired) { - // codeStream.decrStackSize(returnTypeSlotSize); - //} - } - } - if (needFalsePart) { - internalFalseLabel.place(); - if (elseInitStateIndex != -1) { - codeStream.removeNotDefinitelyAssignedVariables( - currentScope, - elseInitStateIndex); - codeStream.addDefinitelyAssignedVariables(currentScope, elseInitStateIndex); - } - valueIfFalse.generateOptimizedBoolean(currentScope, codeStream, trueLabel, falseLabel, valueRequired); + UnconditionalFlowInfo falseInfoWhenFalse = falseFlowInfo + .initsWhenFalse().copy().unconditionalInits(); + if (isValueIfFalseOptimizedTrue) + falseInfoWhenFalse.setReachMode(FlowInfo.UNREACHABLE); - // End of if statement - endifLabel.place(); + mergedInfo = FlowInfo.conditional(trueInfoWhenTrue + .mergedWith(falseInfoWhenTrue), trueInfoWhenFalse + .mergedWith(falseInfoWhenFalse)); } - // May loose some local variable initializations : affecting the local variable attributes - if (mergedInitStateIndex != -1) { - codeStream.removeNotDefinitelyAssignedVariables( - currentScope, - mergedInitStateIndex); - } - // no implicit conversion for boolean values - codeStream.recordPositionsFrom(pc, this.sourceStart); + mergedInitStateIndex = currentScope.methodScope() + .recordInitializationStates(mergedInfo); + mergedInfo.setReachMode(mode); + return mergedInfo; } - public TypeBinding resolveType(BlockScope scope) { - // specs p.368 - constant = NotAConstant; - TypeBinding conditionType = condition.resolveTypeExpecting(scope, BooleanBinding); - TypeBinding valueIfTrueType = valueIfTrue.resolveType(scope); - TypeBinding valueIfFalseType = valueIfFalse.resolveType(scope); - if (conditionType == null || valueIfTrueType == null || valueIfFalseType == null) - return null; + /** + * Code generation for the conditional operator ?: + * + * @param currentScope + * net.sourceforge.phpdt.internal.compiler.lookup.BlockScope + * @param codeStream + * net.sourceforge.phpdt.internal.compiler.codegen.CodeStream + * @param valueRequired + * boolean + */ + // public void generateCode( + // BlockScope currentScope, + // CodeStream codeStream, + // boolean valueRequired) { + // + // int pc = codeStream.position; + // Label endifLabel, falseLabel; + // if (constant != NotAConstant) { + // if (valueRequired) + // codeStream.generateConstant(constant, implicitConversion); + // codeStream.recordPositionsFrom(pc, this.sourceStart); + // return; + // } + // Constant cst = condition.constant; + // Constant condCst = condition.optimizedBooleanConstant(); + // boolean needTruePart = + // !(((cst != NotAConstant) && (cst.booleanValue() == false)) + // || ((condCst != NotAConstant) && (condCst.booleanValue() == false))); + // boolean needFalsePart = + // !(((cst != NotAConstant) && (cst.booleanValue() == true)) + // || ((condCst != NotAConstant) && (condCst.booleanValue() == true))); + // endifLabel = new Label(codeStream); + // + // // Generate code for the condition + // boolean needConditionValue = (cst == NotAConstant) && (condCst == + // NotAConstant); + // condition.generateOptimizedBoolean( + // currentScope, + // codeStream, + // null, + // (falseLabel = new Label(codeStream)), + // needConditionValue); + // + // if (trueInitStateIndex != -1) { + // codeStream.removeNotDefinitelyAssignedVariables( + // currentScope, + // trueInitStateIndex); + // codeStream.addDefinitelyAssignedVariables(currentScope, + // trueInitStateIndex); + // } + // // Then code generation + // if (needTruePart) { + // valueIfTrue.generateCode(currentScope, codeStream, valueRequired); + // if (needFalsePart) { + // // Jump over the else part + // int position = codeStream.position; + // codeStream.goto_(endifLabel); + // codeStream.updateLastRecordedEndPC(position); + // // Tune codestream stack size + // if (valueRequired) { + // codeStream.decrStackSize(returnTypeSlotSize); + // } + // } + // } + // if (needFalsePart) { + // falseLabel.place(); + // if (falseInitStateIndex != -1) { + // codeStream.removeNotDefinitelyAssignedVariables( + // currentScope, + // falseInitStateIndex); + // codeStream.addDefinitelyAssignedVariables(currentScope, + // falseInitStateIndex); + // } + // valueIfFalse.generateCode(currentScope, codeStream, valueRequired); + // // End of if statement + // endifLabel.place(); + // } + // // May loose some local variable initializations : affecting the local + // variable attributes + // if (mergedInitStateIndex != -1) { + // codeStream.removeNotDefinitelyAssignedVariables( + // currentScope, + // mergedInitStateIndex); + // } + // // implicit conversion + // if (valueRequired) + // codeStream.generateImplicitConversion(implicitConversion); + // codeStream.recordPositionsFrom(pc, this.sourceStart); + // } + // + // /** + // * Optimized boolean code generation for the conditional operator ?: + // */ + // public void generateOptimizedBoolean( + // BlockScope currentScope, + // CodeStream codeStream, + // Label trueLabel, + // Label falseLabel, + // boolean valueRequired) { + // + // if ((constant != Constant.NotAConstant) && (constant.typeID() == + // T_boolean) // constant + // || (valueIfTrue.implicitConversion >> 4) != T_boolean) { // non boolean + // values + // super.generateOptimizedBoolean(currentScope, codeStream, trueLabel, + // falseLabel, valueRequired); + // return; + // } + // Constant cst = condition.constant; + // Constant condCst = condition.optimizedBooleanConstant(); + // boolean needTruePart = + // !(((cst != NotAConstant) && (cst.booleanValue() == false)) + // || ((condCst != NotAConstant) && (condCst.booleanValue() == false))); + // boolean needFalsePart = + // !(((cst != NotAConstant) && (cst.booleanValue() == true)) + // || ((condCst != NotAConstant) && (condCst.booleanValue() == true))); + // + // Label internalFalseLabel, endifLabel = new Label(codeStream); + // + // // Generate code for the condition + // boolean needConditionValue = (cst == NotAConstant) && (condCst == + // NotAConstant); + // condition.generateOptimizedBoolean( + // currentScope, + // codeStream, + // null, + // internalFalseLabel = new Label(codeStream), + // needConditionValue); + // + // if (trueInitStateIndex != -1) { + // codeStream.removeNotDefinitelyAssignedVariables( + // currentScope, + // trueInitStateIndex); + // codeStream.addDefinitelyAssignedVariables(currentScope, + // trueInitStateIndex); + // } + // // Then code generation + // if (needTruePart) { + // valueIfTrue.generateOptimizedBoolean(currentScope, codeStream, trueLabel, + // falseLabel, valueRequired); + // + // if (needFalsePart) { + // // Jump over the else part + // int position = codeStream.position; + // codeStream.goto_(endifLabel); + // codeStream.updateLastRecordedEndPC(position); + // // No need to decrement codestream stack size + // // since valueIfTrue was already consumed by branch bytecode + // } + // } + // if (needFalsePart) { + // internalFalseLabel.place(); + // if (falseInitStateIndex != -1) { + // codeStream.removeNotDefinitelyAssignedVariables( + // currentScope, + // falseInitStateIndex); + // codeStream.addDefinitelyAssignedVariables(currentScope, + // falseInitStateIndex); + // } + // valueIfFalse.generateOptimizedBoolean(currentScope, codeStream, + // trueLabel, falseLabel, valueRequired); + // + // // End of if statement + // endifLabel.place(); + // } + // // May loose some local variable initializations : affecting the local + // variable attributes + // if (mergedInitStateIndex != -1) { + // codeStream.removeNotDefinitelyAssignedVariables( + // currentScope, + // mergedInitStateIndex); + // } + // // no implicit conversion for boolean values + // codeStream.updateLastRecordedEndPC(codeStream.position); + // } + // + // public Constant optimizedBooleanConstant() { + // + // return this.optimizedBooleanConstant == null ? this.constant : + // this.optimizedBooleanConstant; + // } + // + // public TypeBinding resolveType(BlockScope scope) { + // // specs p.368 + // constant = NotAConstant; + // TypeBinding conditionType = condition.resolveTypeExpecting(scope, + // BooleanBinding); + // TypeBinding valueIfTrueType = valueIfTrue.resolveType(scope); + // TypeBinding valueIfFalseType = valueIfFalse.resolveType(scope); + // if (conditionType == null || valueIfTrueType == null || valueIfFalseType + // == null) + // return null; + // + // // Propagate the constant value from the valueIfTrue and valueIFFalse + // expression if it is possible + // Constant condConstant, trueConstant, falseConstant; + // if ((condConstant = condition.constant) != NotAConstant + // && (trueConstant = valueIfTrue.constant) != NotAConstant + // && (falseConstant = valueIfFalse.constant) != NotAConstant) { + // // all terms are constant expression so we can propagate the constant + // // from valueIFTrue or valueIfFalse to teh receiver constant + // constant = condConstant.booleanValue() ? trueConstant : falseConstant; + // } + // if (valueIfTrueType == valueIfFalseType) { // harmed the implicit + // conversion + // valueIfTrue.implicitWidening(valueIfTrueType, valueIfTrueType); + // valueIfFalse.implicitConversion = valueIfTrue.implicitConversion; + // if (valueIfTrueType == LongBinding || valueIfTrueType == DoubleBinding) { + // returnTypeSlotSize = 2; + // } + // + // if (valueIfTrueType == BooleanBinding) { + // this.optimizedIfTrueConstant = valueIfTrue.optimizedBooleanConstant(); + // this.optimizedIfFalseConstant = valueIfFalse.optimizedBooleanConstant(); + // + // // Propagate the optimized boolean constant if possible + // if ((condConstant = condition.optimizedBooleanConstant()) != + // NotAConstant) { + // + // this.optimizedBooleanConstant = condConstant.booleanValue() + // ? optimizedIfTrueConstant + // : optimizedIfFalseConstant; + // } + // } + // return this.resolvedType = valueIfTrueType; + // } + // // Determine the return type depending on argument types + // // Numeric types + // if (valueIfTrueType.isNumericType() && valueIfFalseType.isNumericType()) + // { + // // (Short x Byte) or (Byte x Short)" + // if ((valueIfTrueType == ByteBinding && valueIfFalseType == ShortBinding) + // || (valueIfTrueType == ShortBinding && valueIfFalseType == ByteBinding)) + // { + // valueIfTrue.implicitWidening(ShortBinding, valueIfTrueType); + // valueIfFalse.implicitWidening(ShortBinding, valueIfFalseType); + // this.resolvedType = ShortBinding; + // return ShortBinding; + // } + // // x constant(Int) ---> and + // reciprocally + // if ((valueIfTrueType == ByteBinding || valueIfTrueType == ShortBinding || + // valueIfTrueType == CharBinding) + // && (valueIfFalseType == IntBinding + // && valueIfFalse.isConstantValueOfTypeAssignableToType(valueIfFalseType, + // valueIfTrueType))) { + // valueIfTrue.implicitWidening(valueIfTrueType, valueIfTrueType); + // valueIfFalse.implicitWidening(valueIfTrueType, valueIfFalseType); + // this.resolvedType = valueIfTrueType; + // return valueIfTrueType; + // } + // if ((valueIfFalseType == ByteBinding + // || valueIfFalseType == ShortBinding + // || valueIfFalseType == CharBinding) + // && (valueIfTrueType == IntBinding + // && valueIfTrue.isConstantValueOfTypeAssignableToType(valueIfTrueType, + // valueIfFalseType))) { + // valueIfTrue.implicitWidening(valueIfFalseType, valueIfTrueType); + // valueIfFalse.implicitWidening(valueIfFalseType, valueIfFalseType); + // this.resolvedType = valueIfFalseType; + // return valueIfFalseType; + // } + // // Manual binary numeric promotion + // // int + // if (BaseTypeBinding.isNarrowing(valueIfTrueType.id, T_int) + // && BaseTypeBinding.isNarrowing(valueIfFalseType.id, T_int)) { + // valueIfTrue.implicitWidening(IntBinding, valueIfTrueType); + // valueIfFalse.implicitWidening(IntBinding, valueIfFalseType); + // this.resolvedType = IntBinding; + // return IntBinding; + // } + // // long + // if (BaseTypeBinding.isNarrowing(valueIfTrueType.id, T_long) + // && BaseTypeBinding.isNarrowing(valueIfFalseType.id, T_long)) { + // valueIfTrue.implicitWidening(LongBinding, valueIfTrueType); + // valueIfFalse.implicitWidening(LongBinding, valueIfFalseType); + // returnTypeSlotSize = 2; + // this.resolvedType = LongBinding; + // return LongBinding; + // } + // // float + // if (BaseTypeBinding.isNarrowing(valueIfTrueType.id, T_float) + // && BaseTypeBinding.isNarrowing(valueIfFalseType.id, T_float)) { + // valueIfTrue.implicitWidening(FloatBinding, valueIfTrueType); + // valueIfFalse.implicitWidening(FloatBinding, valueIfFalseType); + // this.resolvedType = FloatBinding; + // return FloatBinding; + // } + // // double + // valueIfTrue.implicitWidening(DoubleBinding, valueIfTrueType); + // valueIfFalse.implicitWidening(DoubleBinding, valueIfFalseType); + // returnTypeSlotSize = 2; + // this.resolvedType = DoubleBinding; + // return DoubleBinding; + // } + // // Type references (null null is already tested) + // if ((valueIfTrueType.isBaseType() && valueIfTrueType != NullBinding) + // || (valueIfFalseType.isBaseType() && valueIfFalseType != NullBinding)) { + // scope.problemReporter().conditionalArgumentsIncompatibleTypes( + // this, + // valueIfTrueType, + // valueIfFalseType); + // return null; + // } + // if (valueIfFalseType.isCompatibleWith(valueIfTrueType)) { + // valueIfTrue.implicitWidening(valueIfTrueType, valueIfTrueType); + // valueIfFalse.implicitWidening(valueIfTrueType, valueIfFalseType); + // this.resolvedType = valueIfTrueType; + // return valueIfTrueType; + // } + // if (valueIfTrueType.isCompatibleWith(valueIfFalseType)) { + // valueIfTrue.implicitWidening(valueIfFalseType, valueIfTrueType); + // valueIfFalse.implicitWidening(valueIfFalseType, valueIfFalseType); + // this.resolvedType = valueIfFalseType; + // return valueIfFalseType; + // } + // scope.problemReporter().conditionalArgumentsIncompatibleTypes( + // this, + // valueIfTrueType, + // valueIfFalseType); + // return null; + // } + public StringBuffer printExpressionNoParenthesis(int indent, + StringBuffer output) { - // Propagate the constant value from the valueIfTrue and valueIFFalse expression if it is possible - if (condition.constant != NotAConstant - && valueIfTrue.constant != NotAConstant - && valueIfFalse.constant != NotAConstant) { - // all terms are constant expression so we can propagate the constant - // from valueIFTrue or valueIfFalse to teh receiver constant - constant = - (condition.constant.booleanValue()) - ? valueIfTrue.constant - : valueIfFalse.constant; - } - if (valueIfTrueType == valueIfFalseType) { // harmed the implicit conversion - valueIfTrue.implicitWidening(valueIfTrueType, valueIfTrueType); - valueIfFalse.implicitConversion = valueIfTrue.implicitConversion; - if (valueIfTrueType == LongBinding || valueIfTrueType == DoubleBinding) { - returnTypeSlotSize = 2; - } - this.typeBinding = valueIfTrueType; - return valueIfTrueType; - } - // Determine the return type depending on argument types - // Numeric types - if (valueIfTrueType.isNumericType() && valueIfFalseType.isNumericType()) { - // (Short x Byte) or (Byte x Short)" - if ((valueIfTrueType == ByteBinding && valueIfFalseType == ShortBinding) - || (valueIfTrueType == ShortBinding && valueIfFalseType == ByteBinding)) { - valueIfTrue.implicitWidening(ShortBinding, valueIfTrueType); - valueIfFalse.implicitWidening(ShortBinding, valueIfFalseType); - this.typeBinding = ShortBinding; - return ShortBinding; - } - // x constant(Int) ---> and reciprocally - if ((valueIfTrueType == ByteBinding || valueIfTrueType == ShortBinding || valueIfTrueType == CharBinding) - && (valueIfFalseType == IntBinding - && valueIfFalse.isConstantValueOfTypeAssignableToType(valueIfFalseType, valueIfTrueType))) { - valueIfTrue.implicitWidening(valueIfTrueType, valueIfTrueType); - valueIfFalse.implicitWidening(valueIfTrueType, valueIfFalseType); - this.typeBinding = valueIfTrueType; - return valueIfTrueType; - } - if ((valueIfFalseType == ByteBinding - || valueIfFalseType == ShortBinding - || valueIfFalseType == CharBinding) - && (valueIfTrueType == IntBinding - && valueIfTrue.isConstantValueOfTypeAssignableToType(valueIfTrueType, valueIfFalseType))) { - valueIfTrue.implicitWidening(valueIfFalseType, valueIfTrueType); - valueIfFalse.implicitWidening(valueIfFalseType, valueIfFalseType); - this.typeBinding = valueIfFalseType; - return valueIfFalseType; - } - // Manual binary numeric promotion - // int - if (BaseTypeBinding.isNarrowing(valueIfTrueType.id, T_int) - && BaseTypeBinding.isNarrowing(valueIfFalseType.id, T_int)) { - valueIfTrue.implicitWidening(IntBinding, valueIfTrueType); - valueIfFalse.implicitWidening(IntBinding, valueIfFalseType); - this.typeBinding = IntBinding; - return IntBinding; - } - // long - if (BaseTypeBinding.isNarrowing(valueIfTrueType.id, T_long) - && BaseTypeBinding.isNarrowing(valueIfFalseType.id, T_long)) { - valueIfTrue.implicitWidening(LongBinding, valueIfTrueType); - valueIfFalse.implicitWidening(LongBinding, valueIfFalseType); - returnTypeSlotSize = 2; - this.typeBinding = LongBinding; - return LongBinding; - } - // float - if (BaseTypeBinding.isNarrowing(valueIfTrueType.id, T_float) - && BaseTypeBinding.isNarrowing(valueIfFalseType.id, T_float)) { - valueIfTrue.implicitWidening(FloatBinding, valueIfTrueType); - valueIfFalse.implicitWidening(FloatBinding, valueIfFalseType); - this.typeBinding = FloatBinding; - return FloatBinding; - } - // double - valueIfTrue.implicitWidening(DoubleBinding, valueIfTrueType); - valueIfFalse.implicitWidening(DoubleBinding, valueIfFalseType); - returnTypeSlotSize = 2; - this.typeBinding = DoubleBinding; - return DoubleBinding; - } - // Type references (null null is already tested) - if ((valueIfTrueType.isBaseType() && valueIfTrueType != NullBinding) - || (valueIfFalseType.isBaseType() && valueIfFalseType != NullBinding)) { - scope.problemReporter().conditionalArgumentsIncompatibleTypes( - this, - valueIfTrueType, - valueIfFalseType); - return null; - } - if (scope.areTypesCompatible(valueIfFalseType, valueIfTrueType)) { - valueIfTrue.implicitWidening(valueIfTrueType, valueIfTrueType); - valueIfFalse.implicitWidening(valueIfTrueType, valueIfFalseType); - this.typeBinding = valueIfTrueType; - return valueIfTrueType; - } - if (scope.areTypesCompatible(valueIfTrueType, valueIfFalseType)) { - valueIfTrue.implicitWidening(valueIfFalseType, valueIfTrueType); - valueIfFalse.implicitWidening(valueIfFalseType, valueIfFalseType); - this.typeBinding = valueIfFalseType; - return valueIfFalseType; - } - scope.problemReporter().conditionalArgumentsIncompatibleTypes( - this, - valueIfTrueType, - valueIfFalseType); - return null; + condition.printExpression(indent, output).append(" ? "); //$NON-NLS-1$ + valueIfTrue.printExpression(0, output).append(" : "); //$NON-NLS-1$ + return valueIfFalse.printExpression(0, output); } - + public String toStringExpressionNoParenthesis() { return condition.toStringExpression() + " ? " + //$NON-NLS-1$ - valueIfTrue.toStringExpression() + " : " + //$NON-NLS-1$ - valueIfFalse.toStringExpression(); + valueIfTrue.toStringExpression() + " : " + //$NON-NLS-1$ + valueIfFalse.toStringExpression(); } - public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) { + public void traverse(ASTVisitor visitor, BlockScope scope) { if (visitor.visit(this, scope)) { condition.traverse(visitor, scope); valueIfTrue.traverse(visitor, scope); @@ -410,4 +475,4 @@ public class ConditionalExpression extends OperatorExpression { } visitor.endVisit(this, scope); } -} \ No newline at end of file +}