X-Git-Url: http://secure.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..9bd4807 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,29 +1,34 @@ /******************************************************************************* - * 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; + 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( @@ -42,367 +47,376 @@ public class ConditionalExpression extends OperatorExpression { 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); + + // 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); - 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-false part + FlowInfo falseFlowInfo = flowInfo.initsWhenFalse().copy(); + if (isConditionOptimizedTrue) { + falseFlowInfo.setReachMode(FlowInfo.UNREACHABLE); } + falseInitStateIndex = currentScope.methodScope().recordInitializationStates(falseFlowInfo); + falseFlowInfo = valueIfFalse.analyseCode(currentScope, flowContext, falseFlowInfo); + + // 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; + + cst = this.optimizedIfFalseConstant; + boolean isValueIfFalseOptimizedTrue = cst != null && cst != NotAConstant && cst.booleanValue() == true; + boolean isValueIfFalseOptimizedFalse = cst != null && cst != NotAConstant && cst.booleanValue() == false; + + UnconditionalFlowInfo trueInfoWhenTrue = trueFlowInfo.initsWhenTrue().copy().unconditionalInits(); + if (isValueIfTrueOptimizedFalse) trueInfoWhenTrue.setReachMode(FlowInfo.UNREACHABLE); - // 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); + UnconditionalFlowInfo falseInfoWhenTrue = falseFlowInfo.initsWhenTrue().copy().unconditionalInits(); + if (isValueIfFalseOptimizedFalse) falseInfoWhenTrue.setReachMode(FlowInfo.UNREACHABLE); + + UnconditionalFlowInfo trueInfoWhenFalse = trueFlowInfo.initsWhenFalse().copy().unconditionalInits(); + if (isValueIfTrueOptimizedTrue) trueInfoWhenFalse.setReachMode(FlowInfo.UNREACHABLE); - // propagate analysis - trueInfo = valueIfTrue.analyseCode(currentScope, flowContext, trueInfo.copy()); - falseInfo = - valueIfFalse.analyseCode(currentScope, flowContext, falseInfo.copy()); + UnconditionalFlowInfo falseInfoWhenFalse = falseFlowInfo.initsWhenFalse().copy().unconditionalInits(); + if (isValueIfFalseOptimizedTrue) falseInfoWhenFalse.setReachMode(FlowInfo.UNREACHABLE); - // 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()); - */ + mergedInfo = + FlowInfo.conditional( + trueInfoWhenTrue.mergedWith(falseInfoWhenTrue), + trueInfoWhenFalse.mergedWith(falseInfoWhenFalse)); + } mergedInitStateIndex = currentScope.methodScope().recordInitializationStates(mergedInfo); + mergedInfo.setReachMode(mode); 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 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.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); - - 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); - } - - /** - * 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; - } - 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))); - - 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 (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); - - // 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.recordPositionsFrom(pc, this.sourceStart); +// 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) { + + condition.printExpression(indent, output).append(" ? "); //$NON-NLS-1$ + valueIfTrue.printExpression(0, output).append(" : "); //$NON-NLS-1$ + return valueIfFalse.printExpression(0, output); } - - 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 - 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; - } - public String toStringExpressionNoParenthesis() { return condition.toStringExpression() + " ? " + //$NON-NLS-1$ 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 +424,4 @@ public class ConditionalExpression extends OperatorExpression { } visitor.endVisit(this, scope); } -} \ No newline at end of file +}