<s> package org . eclipse . jdt . internal . compiler . ast ; import org . eclipse . jdt . internal . compiler . ASTVisitor ; import org . eclipse . jdt . internal . compiler . impl . * ; import org . eclipse . jdt . internal . compiler . classfmt . ClassFileConstants ; import org . eclipse . jdt . internal . compiler . codegen . * ; import org . eclipse . jdt . internal . compiler . flow . * ; import org . eclipse . jdt . internal . compiler . lookup . * ; public class ConditionalExpression extends OperatorExpression { public Expression condition , valueIfTrue , valueIfFalse ; public Constant optimizedBooleanConstant ; public Constant optimizedIfTrueConstant ; public Constant optimizedIfFalseConstant ; int trueInitStateIndex = - 1 ; int falseInitStateIndex = - 1 ; int mergedInitStateIndex = - 1 ; private int nullStatus = FlowInfo . UNKNOWN ; public ConditionalExpression ( Expression condition , Expression valueIfTrue , Expression valueIfFalse ) { this . condition = condition ; this . valueIfTrue = valueIfTrue ; this . valueIfFalse = valueIfFalse ; this . sourceStart = condition . sourceStart ; this . sourceEnd = valueIfFalse . sourceEnd ; } public FlowInfo analyseCode ( BlockScope currentScope , FlowContext flowContext , FlowInfo flowInfo ) { int initialComplaintLevel = ( flowInfo . reachMode ( ) & FlowInfo . UNREACHABLE ) != 0 ? Statement . COMPLAINED_FAKE_REACHABLE : Statement . NOT_COMPLAINED ; Constant cst = this . condition . optimizedBooleanConstant ( ) ; boolean isConditionOptimizedTrue = cst != Constant . NotAConstant && cst . booleanValue ( ) == true ; boolean isConditionOptimizedFalse = cst != Constant . NotAConstant && cst . booleanValue ( ) == false ; int mode = flowInfo . reachMode ( ) ; flowInfo = this . condition . analyseCode ( currentScope , flowContext , flowInfo , cst == Constant . NotAConstant ) ; FlowInfo trueFlowInfo = flowInfo . initsWhenTrue ( ) . copy ( ) ; if ( isConditionOptimizedFalse ) { if ( ( mode & FlowInfo . UNREACHABLE ) == 0 ) { trueFlowInfo . setReachMode ( FlowInfo . UNREACHABLE_OR_DEAD ) ; } if ( ! isKnowDeadCodePattern ( this . condition ) || currentScope . compilerOptions ( ) . reportDeadCodeInTrivialIfStatement ) { this . valueIfTrue . complainIfUnreachable ( trueFlowInfo , currentScope , initialComplaintLevel , false ) ; } } this . trueInitStateIndex = currentScope . methodScope ( ) . recordInitializationStates ( trueFlowInfo ) ; trueFlowInfo = this . valueIfTrue . analyseCode ( currentScope , flowContext , trueFlowInfo ) ; FlowInfo falseFlowInfo = flowInfo . initsWhenFalse ( ) . copy ( ) ; if ( isConditionOptimizedTrue ) { if ( ( mode & FlowInfo . UNREACHABLE ) == 0 ) { falseFlowInfo . setReachMode ( FlowInfo . UNREACHABLE_OR_DEAD ) ; } if ( ! isKnowDeadCodePattern ( this . condition ) || currentScope . compilerOptions ( ) . reportDeadCodeInTrivialIfStatement ) { this . valueIfFalse . complainIfUnreachable ( falseFlowInfo , currentScope , initialComplaintLevel , true ) ; } } this . falseInitStateIndex = currentScope . methodScope ( ) . recordInitializationStates ( falseFlowInfo ) ; falseFlowInfo = this . valueIfFalse . analyseCode ( currentScope , flowContext , falseFlowInfo ) ; FlowInfo mergedInfo ; if ( isConditionOptimizedTrue ) { mergedInfo = trueFlowInfo . addPotentialInitializationsFrom ( falseFlowInfo ) ; this . nullStatus = this . valueIfTrue . nullStatus ( trueFlowInfo ) ; } else if ( isConditionOptimizedFalse ) { mergedInfo = falseFlowInfo . addPotentialInitializationsFrom ( trueFlowInfo ) ; this . nullStatus = this . valueIfFalse . nullStatus ( falseFlowInfo ) ; } else { computeNullStatus ( trueFlowInfo , falseFlowInfo ) ; cst = this . optimizedIfTrueConstant ; boolean isValueIfTrueOptimizedTrue = cst != null && cst != Constant . NotAConstant && cst . booleanValue ( ) == true ; boolean isValueIfTrueOptimizedFalse = cst != null && cst != Constant . NotAConstant && cst . booleanValue ( ) == false ; cst = this . optimizedIfFalseConstant ; boolean isValueIfFalseOptimizedTrue = cst != null && cst != Constant . NotAConstant && cst . booleanValue ( ) == true ; boolean isValueIfFalseOptimizedFalse = cst != null && cst != Constant . NotAConstant && cst . booleanValue ( ) == false ; UnconditionalFlowInfo trueFlowTowardsTrue = trueFlowInfo . initsWhenTrue ( ) . unconditionalCopy ( ) ; UnconditionalFlowInfo falseFlowTowardsTrue = falseFlowInfo . initsWhenTrue ( ) . unconditionalCopy ( ) ; UnconditionalFlowInfo trueFlowTowardsFalse = trueFlowInfo . initsWhenFalse ( ) . unconditionalInits ( ) ; UnconditionalFlowInfo falseFlowTowardsFalse = falseFlowInfo . initsWhenFalse ( ) . unconditionalInits ( ) ; if ( isValueIfTrueOptimizedFalse ) { trueFlowTowardsTrue . setReachMode ( FlowInfo . UNREACHABLE_OR_DEAD ) ; } if ( isValueIfFalseOptimizedFalse ) { falseFlowTowardsTrue . setReachMode ( FlowInfo . UNREACHABLE_OR_DEAD ) ; } if ( isValueIfTrueOptimizedTrue ) { trueFlowTowardsFalse . setReachMode ( FlowInfo . UNREACHABLE_OR_DEAD ) ; } if ( isValueIfFalseOptimizedTrue ) { falseFlowTowardsFalse . setReachMode ( FlowInfo . UNREACHABLE_OR_DEAD ) ; } mergedInfo = FlowInfo . conditional ( trueFlowTowardsTrue . mergedWith ( falseFlowTowardsTrue ) , trueFlowTowardsFalse . mergedWith ( falseFlowTowardsFalse ) ) ; } this . mergedInitStateIndex = currentScope . methodScope ( ) . recordInitializationStates ( mergedInfo ) ; mergedInfo . setReachMode ( mode ) ; return mergedInfo ; } private void computeNullStatus ( FlowInfo trueBranchInfo , FlowInfo falseBranchInfo ) { int ifTrueNullStatus = this . valueIfTrue . nullStatus ( trueBranchInfo ) ; int ifFalseNullStatus = this . valueIfFalse . nullStatus ( falseBranchInfo ) ; if ( ifTrueNullStatus == ifFalseNullStatus ) { this . nullStatus = ifTrueNullStatus ; return ; } if ( trueBranchInfo . reachMode ( ) != FlowInfo . REACHABLE ) { this . nullStatus = ifFalseNullStatus ; return ; } if ( falseBranchInfo . reachMode ( ) != FlowInfo . REACHABLE ) { this . nullStatus = ifTrueNullStatus ; return ; } int status = 0 ; int combinedStatus = ifTrueNullStatus | ifFalseNullStatus ; if ( ( combinedStatus & ( FlowInfo . NULL | FlowInfo . POTENTIALLY_NULL ) ) != 0 ) status |= FlowInfo . POTENTIALLY_NULL ; if ( ( combinedStatus & ( FlowInfo . NON_NULL | FlowInfo . POTENTIALLY_NON_NULL ) ) != 0 ) status |= FlowInfo . POTENTIALLY_NON_NULL ; if ( ( combinedStatus & ( FlowInfo . UNKNOWN | FlowInfo . POTENTIALLY_UNKNOWN ) ) != 0 ) status |= FlowInfo . POTENTIALLY_UNKNOWN ; if ( status > 0 ) this . nullStatus = status ; } public void generateCode ( BlockScope currentScope , CodeStream codeStream , boolean valueRequired ) { int pc = codeStream . position ; BranchLabel endifLabel , falseLabel ; if ( this . constant != Constant . NotAConstant ) { if ( valueRequired ) codeStream . generateConstant ( this . constant , this . implicitConversion ) ; codeStream . recordPositionsFrom ( pc , this . sourceStart ) ; return ; } Constant cst = this . condition . optimizedBooleanConstant ( ) ; boolean needTruePart = ! ( cst != Constant . NotAConstant && cst . booleanValue ( ) == false ) ; boolean needFalsePart = ! ( cst != Constant . NotAConstant && cst . booleanValue ( ) == true ) ; endifLabel = new BranchLabel ( codeStream ) ; falseLabel = new BranchLabel ( codeStream ) ; falseLabel . tagBits |= BranchLabel . USED ; this . condition . generateOptimizedBoolean ( currentScope , codeStream , null , falseLabel , cst == Constant . NotAConstant ) ; if ( this . trueInitStateIndex != - 1 ) { codeStream . removeNotDefinitelyAssignedVariables ( currentScope , this . trueInitStateIndex ) ; codeStream . addDefinitelyAssignedVariables ( currentScope , this . trueInitStateIndex ) ; } if ( needTruePart ) { this . valueIfTrue . generateCode ( currentScope , codeStream , valueRequired ) ; if ( needFalsePart ) { int position = codeStream . position ; codeStream . goto_ ( endifLabel ) ; codeStream . recordPositionsFrom ( position , this . valueIfTrue . sourceEnd ) ; if ( valueRequired ) { switch ( this . resolvedType . id ) { case TypeIds . T_long : case TypeIds . T_double : codeStream . decrStackSize ( 2 ) ; break ; default : codeStream . decrStackSize ( 1 ) ; break ; } } } } if ( needFalsePart ) { if ( this . falseInitStateIndex != - 1 ) { codeStream . removeNotDefinitelyAssignedVariables ( currentScope , this . falseInitStateIndex ) ; codeStream . addDefinitelyAssignedVariables ( currentScope , this . falseInitStateIndex ) ; } if ( falseLabel . forwardReferenceCount ( ) > 0 ) { falseLabel . place ( ) ; } this . valueIfFalse . generateCode ( currentScope , codeStream , valueRequired ) ; if ( valueRequired ) { codeStream . recordExpressionType ( this . resolvedType ) ; } if ( needTruePart ) { endifLabel . place ( ) ; } } if ( this . mergedInitStateIndex != - 1 ) { codeStream . removeNotDefinitelyAssignedVariables ( currentScope , this . mergedInitStateIndex ) ; } if ( valueRequired ) codeStream . generateImplicitConversion ( this . implicitConversion ) ; codeStream . recordPositionsFrom ( pc , this . sourceStart ) ; } public void generateOptimizedBoolean ( BlockScope currentScope , CodeStream codeStream , BranchLabel trueLabel , BranchLabel falseLabel , boolean valueRequired ) { int pc = codeStream . position ; if ( ( this . constant != Constant . NotAConstant ) && ( this . constant . typeID ( ) == T_boolean ) || ( ( this . valueIfTrue . implicitConversion & IMPLICIT_CONVERSION_MASK ) >> 4 ) != T_boolean ) { super . generateOptimizedBoolean ( currentScope , codeStream , trueLabel , falseLabel , valueRequired ) ; return ; } Constant cst = this . condition . constant ; Constant condCst = this . condition . optimizedBooleanConstant ( ) ; boolean needTruePart = ! ( ( ( cst != Constant . NotAConstant ) && ( cst . booleanValue ( ) == false ) ) || ( ( condCst != Constant . NotAConstant ) && ( condCst . booleanValue ( ) == false ) ) ) ; boolean needFalsePart = ! ( ( ( cst != Constant . NotAConstant ) && ( cst . booleanValue ( ) == true ) ) || ( ( condCst != Constant . NotAConstant ) && ( condCst . booleanValue ( ) == true ) ) ) ; BranchLabel internalFalseLabel , endifLabel = new BranchLabel ( codeStream ) ; boolean needConditionValue = ( cst == Constant . NotAConstant ) && ( condCst == Constant . NotAConstant ) ; this . condition . generateOptimizedBoolean ( currentScope , codeStream , null , internalFalseLabel = new BranchLabel ( codeStream ) , needConditionValue ) ; if ( this . trueInitStateIndex != - 1 ) { codeStream . removeNotDefinitelyAssignedVariables ( currentScope , this . trueInitStateIndex ) ; codeStream . addDefinitelyAssignedVariables ( currentScope , this . trueInitStateIndex ) ; } if ( needTruePart ) { this . valueIfTrue . generateOptimizedBoolean ( currentScope , codeStream , trueLabel , falseLabel , valueRequired ) ; if ( needFalsePart ) { JumpEndif : { if ( falseLabel == null ) { if ( trueLabel != null ) { cst = this . optimizedIfTrueConstant ; boolean isValueIfTrueOptimizedTrue = cst != null && cst != Constant . NotAConstant && cst . booleanValue ( ) == true ; if ( isValueIfTrueOptimizedTrue ) break JumpEndif ; } } else { if ( trueLabel == null ) { cst = this . optimizedIfTrueConstant ; boolean isValueIfTrueOptimizedFalse = cst != null && cst != Constant . NotAConstant && cst . booleanValue ( ) == false ; if ( isValueIfTrueOptimizedFalse ) break JumpEndif ; } else { } } int position = codeStream . position ; codeStream . goto_ ( endifLabel ) ; codeStream . recordPositionsFrom ( position , this . valueIfTrue . sourceEnd ) ; } } } if ( needFalsePart ) { internalFalseLabel . place ( ) ; if ( this . falseInitStateIndex != - 1 ) { codeStream . removeNotDefinitelyAssignedVariables ( currentScope , this . falseInitStateIndex ) ; codeStream . addDefinitelyAssignedVariables ( currentScope , this . falseInitStateIndex ) ; } this . valueIfFalse . generateOptimizedBoolean ( currentScope , codeStream , trueLabel , falseLabel , valueRequired ) ; endifLabel . place ( ) ; } if ( this . mergedInitStateIndex != - 1 ) { codeStream . removeNotDefinitelyAssignedVariables ( currentScope , this . mergedInitStateIndex ) ; } codeStream . recordPositionsFrom ( pc , this . sourceEnd ) ; } public int nullStatus ( FlowInfo flowInfo ) { return this . nullStatus ; } public Constant optimizedBooleanConstant ( ) { return this . optimizedBooleanConstant == null ? this . constant : this . optimizedBooleanConstant ; } public StringBuffer printExpressionNoParenthesis ( int indent , StringBuffer output ) { this . condition . printExpression ( indent , output ) . append ( " ? " ) ; this . valueIfTrue . printExpression ( 0 , output ) . append ( " : " ) ; return this . valueIfFalse . printExpression ( 0 , output ) ; } public TypeBinding resolveType ( BlockScope scope ) { this . constant = Constant . NotAConstant ; LookupEnvironment env = scope . environment ( ) ; boolean use15specifics = scope . compilerOptions ( ) . sourceLevel >= ClassFileConstants . JDK1_5 ; TypeBinding conditionType = this . condition . resolveTypeExpecting ( scope , TypeBinding . BOOLEAN ) ; this . condition . computeConversion ( scope , TypeBinding . BOOLEAN , conditionType ) ; if ( this . valueIfTrue instanceof CastExpression ) this . valueIfTrue . bits |= DisableUnnecessaryCastCheck ; TypeBinding originalValueIfTrueType = this . valueIfTrue . resolveType ( scope ) ; if ( this . valueIfFalse instanceof CastExpression ) this . valueIfFalse . bits |= DisableUnnecessaryCastCheck ; TypeBinding originalValueIfFalseType = this . valueIfFalse . resolveType ( scope ) ; if ( conditionType == null || originalValueIfTrueType == null || originalValueIfFalseType == null ) return null ; TypeBinding valueIfTrueType = originalValueIfTrueType ; TypeBinding valueIfFalseType = originalValueIfFalseType ; if ( use15specifics && valueIfTrueType != valueIfFalseType ) { if ( valueIfTrueType . isBaseType ( ) ) { if ( valueIfFalseType . isBaseType ( ) ) { if ( valueIfTrueType == TypeBinding . NULL ) { valueIfFalseType = env . computeBoxingType ( valueIfFalseType ) ; } else if ( valueIfFalseType == TypeBinding . NULL ) { valueIfTrueType = env . computeBoxingType ( valueIfTrueType ) ; } } else { TypeBinding unboxedIfFalseType = valueIfFalseType . isBaseType ( ) ? valueIfFalseType : env . computeBoxingType ( valueIfFalseType ) ; if ( valueIfTrueType . isNumericType ( ) && unboxedIfFalseType . isNumericType ( ) ) { valueIfFalseType = unboxedIfFalseType ; } else if ( valueIfTrueType != TypeBinding . NULL ) { valueIfFalseType = env . computeBoxingType ( valueIfFalseType ) ; } } } else if ( valueIfFalseType . isBaseType ( ) ) { TypeBinding unboxedIfTrueType = valueIfTrueType . isBaseType ( ) ? valueIfTrueType : env . computeBoxingType ( valueIfTrueType ) ; if ( unboxedIfTrueType . isNumericType ( ) && valueIfFalseType . isNumericType ( ) ) { valueIfTrueType = unboxedIfTrueType ; } else if ( valueIfFalseType != TypeBinding . NULL ) { valueIfTrueType = env . computeBoxingType ( valueIfTrueType ) ; } } else { TypeBinding unboxedIfTrueType = env . computeBoxingType ( valueIfTrueType ) ; TypeBinding unboxedIfFalseType = env . computeBoxingType ( valueIfFalseType ) ; if ( unboxedIfTrueType . isNumericType ( ) && unboxedIfFalseType . isNumericType ( ) ) { valueIfTrueType = unboxedIfTrueType ; valueIfFalseType = unboxedIfFalseType ; } } } Constant condConstant , trueConstant , falseConstant ; if ( ( condConstant = this . condition . constant ) != Constant . NotAConstant && ( trueConstant = this . valueIfTrue . constant ) != Constant . NotAConstant && ( falseConstant = this . valueIfFalse . constant ) != Constant . NotAConstant ) { this . constant = condConstant . booleanValue ( ) ? trueConstant : falseConstant ; } if ( valueIfTrueType == valueIfFalseType ) { this . valueIfTrue . computeConversion ( scope , valueIfTrueType , originalValueIfTrueType ) ; this . valueIfFalse . computeConversion ( scope , valueIfFalseType , originalValueIfFalseType ) ; if ( valueIfTrueType == TypeBinding . BOOLEAN ) { this . optimizedIfTrueConstant = this . valueIfTrue . optimizedBooleanConstant ( ) ; this . optimizedIfFalseConstant = this . valueIfFalse . optimizedBooleanConstant ( ) ; if ( this . optimizedIfTrueConstant != Constant . NotAConstant && this . optimizedIfFalseConstant != Constant . NotAConstant && this . optimizedIfTrueConstant . booleanValue ( ) == this . optimizedIfFalseConstant . booleanValue ( ) ) { this . optimizedBooleanConstant = this . optimizedIfTrueConstant ; } else if ( ( condConstant = this . condition . optimizedBooleanConstant ( ) ) != Constant . NotAConstant ) { this . optimizedBooleanConstant = condConstant . booleanValue ( ) ? this . optimizedIfTrueConstant : this . optimizedIfFalseConstant ; } } return this . resolvedType = valueIfTrueType ; } if ( valueIfTrueType . isNumericType ( ) && valueIfFalseType . isNumericType ( ) ) { if ( ( valueIfTrueType == TypeBinding . BYTE && valueIfFalseType == TypeBinding . SHORT ) || ( valueIfTrueType == TypeBinding . SHORT && valueIfFalseType == TypeBinding . BYTE ) ) { this . valueIfTrue . computeConversion ( scope , TypeBinding . SHORT , originalValueIfTrueType ) ; this . valueIfFalse . computeConversion ( scope , TypeBinding . SHORT , originalValueIfFalseType ) ; return this . resolvedType = TypeBinding . SHORT ; } if ( ( valueIfTrueType == TypeBinding . BYTE || valueIfTrueType == TypeBinding . SHORT || valueIfTrueType == TypeBinding . CHAR ) && ( valueIfFalseType == TypeBinding . INT && this . valueIfFalse . isConstantValueOfTypeAssignableToType ( valueIfFalseType , valueIfTrueType ) ) ) { this . valueIfTrue . computeConversion ( scope , valueIfTrueType , originalValueIfTrueType ) ; this . valueIfFalse . computeConversion ( scope , valueIfTrueType , originalValueIfFalseType ) ; return this . resolvedType = valueIfTrueType ; } if ( ( valueIfFalseType == TypeBinding . BYTE || valueIfFalseType == TypeBinding . SHORT || valueIfFalseType == TypeBinding . CHAR ) && ( valueIfTrueType == TypeBinding . INT && this . valueIfTrue . isConstantValueOfTypeAssignableToType ( valueIfTrueType , valueIfFalseType ) ) ) { this . valueIfTrue . computeConversion ( scope , valueIfFalseType , originalValueIfTrueType ) ; this . valueIfFalse . computeConversion ( scope , valueIfFalseType , originalValueIfFalseType ) ; return this . resolvedType = valueIfFalseType ; } if ( BaseTypeBinding . isNarrowing ( valueIfTrueType . id , T_int ) && BaseTypeBinding . isNarrowing ( valueIfFalseType . id , T_int ) ) { this . valueIfTrue . computeConversion ( scope , TypeBinding . INT , originalValueIfTrueType ) ; this . valueIfFalse . computeConversion ( scope , TypeBinding . INT , originalValueIfFalseType ) ; return this . resolvedType = TypeBinding . INT ; } if ( BaseTypeBinding . isNarrowing ( valueIfTrueType . id , T_long ) && BaseTypeBinding . isNarrowing ( valueIfFalseType . id , T_long ) ) { this . valueIfTrue . computeConversion ( scope , TypeBinding . LONG , originalValueIfTrueType ) ; this . valueIfFalse . computeConversion ( scope , TypeBinding . LONG , originalValueIfFalseType ) ; return this . resolvedType = TypeBinding . LONG ; } if ( BaseTypeBinding . isNarrowing ( valueIfTrueType . id , T_float ) && BaseTypeBinding . isNarrowing ( valueIfFalseType . id , T_float ) ) { this . valueIfTrue . computeConversion ( scope , TypeBinding . FLOAT , originalValueIfTrueType ) ; this . valueIfFalse . computeConversion ( scope , TypeBinding . FLOAT , originalValueIfFalseType ) ; return this . resolvedType = TypeBinding . FLOAT ; } this . valueIfTrue . computeConversion ( scope , TypeBinding . DOUBLE , originalValueIfTrueType ) ; this . valueIfFalse . computeConversion ( scope , TypeBinding . DOUBLE , originalValueIfFalseType ) ; return this . resolvedType = TypeBinding . DOUBLE ; } if ( valueIfTrueType . isBaseType ( ) && valueIfTrueType != TypeBinding . NULL ) { if ( use15specifics ) { valueIfTrueType = env . computeBoxingType ( valueIfTrueType ) ; } else { scope . problemReporter ( ) . conditionalArgumentsIncompatibleTypes ( this , valueIfTrueType , valueIfFalseType ) ; return null ; } } if ( valueIfFalseType . isBaseType ( ) && valueIfFalseType != TypeBinding . NULL ) { if ( use15specifics ) { valueIfFalseType = env . computeBoxingType ( valueIfFalseType ) ; } else { scope . problemReporter ( ) . conditionalArgumentsIncompatibleTypes ( this , valueIfTrueType , valueIfFalseType ) ; return null ; } } if ( use15specifics ) { TypeBinding commonType = null ; if ( valueIfTrueType == TypeBinding . NULL ) { commonType = valueIfFalseType ; } else if ( valueIfFalseType == TypeBinding . NULL ) { commonType = valueIfTrueType ; } else { commonType = scope . lowerUpperBound ( new TypeBinding [ ] { valueIfTrueType , valueIfFalseType } ) ; } if ( commonType != null ) { this . valueIfTrue . computeConversion ( scope , commonType , originalValueIfTrueType ) ; this . valueIfFalse . computeConversion ( scope , commonType , originalValueIfFalseType ) ; return this . resolvedType = commonType . capture ( scope , this . sourceEnd ) ; } } else { if ( valueIfFalseType . isCompatibleWith ( valueIfTrueType ) ) { this . valueIfTrue . computeConversion ( scope , valueIfTrueType , originalValueIfTrueType ) ; this . valueIfFalse . computeConversion ( scope , valueIfTrueType , originalValueIfFalseType ) ; return this . resolvedType = valueIfTrueType ; } else if ( valueIfTrueType . isCompatibleWith ( valueIfFalseType ) ) { this . valueIfTrue . computeConversion ( scope , valueIfFalseType , originalValueIfTrueType ) ; this . valueIfFalse . computeConversion ( scope , valueIfFalseType , originalValueIfFalseType ) ; return this . resolvedType = valueIfFalseType ; } } scope . problemReporter ( ) . conditionalArgumentsIncompatibleTypes ( this , valueIfTrueType , valueIfFalseType ) ; return null ; } public void traverse ( ASTVisitor visitor , BlockScope scope ) { if ( visitor . visit ( this , scope ) ) { this . condition . traverse ( visitor , scope ) ; this . valueIfTrue . traverse ( visitor , scope ) ; this . valueIfFalse . traverse ( visitor , scope ) ; } visitor . endVisit ( this , scope ) ; } } </s>