KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > compiler > ast > ConditionalExpression


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.jdt.internal.compiler.ast;
12
13 import org.eclipse.jdt.internal.compiler.ASTVisitor;
14 import org.eclipse.jdt.internal.compiler.impl.*;
15 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
16 import org.eclipse.jdt.internal.compiler.codegen.*;
17 import org.eclipse.jdt.internal.compiler.flow.*;
18 import org.eclipse.jdt.internal.compiler.lookup.*;
19
20 public class ConditionalExpression extends OperatorExpression {
21
22     public Expression condition, valueIfTrue, valueIfFalse;
23     public Constant optimizedBooleanConstant;
24     public Constant optimizedIfTrueConstant;
25     public Constant optimizedIfFalseConstant;
26     
27     // for local variables table attributes
28
int trueInitStateIndex = -1;
29     int falseInitStateIndex = -1;
30     int mergedInitStateIndex = -1;
31     
32     public ConditionalExpression(
33         Expression condition,
34         Expression valueIfTrue,
35         Expression valueIfFalse) {
36         this.condition = condition;
37         this.valueIfTrue = valueIfTrue;
38         this.valueIfFalse = valueIfFalse;
39         sourceStart = condition.sourceStart;
40         sourceEnd = valueIfFalse.sourceEnd;
41     }
42
43 public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext,
44         FlowInfo flowInfo) {
45         Constant cst = this.condition.optimizedBooleanConstant();
46         boolean isConditionOptimizedTrue = cst != Constant.NotAConstant && cst.booleanValue() == true;
47         boolean isConditionOptimizedFalse = cst != Constant.NotAConstant && cst.booleanValue() == false;
48
49         int mode = flowInfo.reachMode();
50         flowInfo = condition.analyseCode(currentScope, flowContext, flowInfo, cst == Constant.NotAConstant);
51         
52         // process the if-true part
53
FlowInfo trueFlowInfo = flowInfo.initsWhenTrue().copy();
54         if (isConditionOptimizedFalse) {
55             trueFlowInfo.setReachMode(FlowInfo.UNREACHABLE);
56         }
57         trueInitStateIndex = currentScope.methodScope().recordInitializationStates(trueFlowInfo);
58         trueFlowInfo = valueIfTrue.analyseCode(currentScope, flowContext, trueFlowInfo);
59
60         // process the if-false part
61
FlowInfo falseFlowInfo = flowInfo.initsWhenFalse().copy();
62         if (isConditionOptimizedTrue) {
63             falseFlowInfo.setReachMode(FlowInfo.UNREACHABLE);
64         }
65         falseInitStateIndex = currentScope.methodScope().recordInitializationStates(falseFlowInfo);
66         falseFlowInfo = valueIfFalse.analyseCode(currentScope, flowContext, falseFlowInfo);
67
68         // merge if-true & if-false initializations
69
FlowInfo mergedInfo;
70         if (isConditionOptimizedTrue){
71             mergedInfo = trueFlowInfo.addPotentialInitializationsFrom(falseFlowInfo);
72         } else if (isConditionOptimizedFalse) {
73             mergedInfo = falseFlowInfo.addPotentialInitializationsFrom(trueFlowInfo);
74         } else {
75             // if ((t && (v = t)) ? t : t && (v = f)) r = v; -- ok
76
cst = this.optimizedIfTrueConstant;
77             boolean isValueIfTrueOptimizedTrue = cst != null && cst != Constant.NotAConstant && cst.booleanValue() == true;
78             boolean isValueIfTrueOptimizedFalse = cst != null && cst != Constant.NotAConstant && cst.booleanValue() == false;
79             
80             cst = this.optimizedIfFalseConstant;
81             boolean isValueIfFalseOptimizedTrue = cst != null && cst != Constant.NotAConstant && cst.booleanValue() == true;
82             boolean isValueIfFalseOptimizedFalse = cst != null && cst != Constant.NotAConstant && cst.booleanValue() == false;
83
84             UnconditionalFlowInfo trueInfoWhenTrue = trueFlowInfo.initsWhenTrue().unconditionalCopy();
85             UnconditionalFlowInfo falseInfoWhenTrue = falseFlowInfo.initsWhenTrue().unconditionalCopy();
86             UnconditionalFlowInfo trueInfoWhenFalse = trueFlowInfo.initsWhenFalse().unconditionalInits();
87             UnconditionalFlowInfo falseInfoWhenFalse = falseFlowInfo.initsWhenFalse().unconditionalInits();
88             if (isValueIfTrueOptimizedFalse) trueInfoWhenTrue.setReachMode(FlowInfo.UNREACHABLE);
89             if (isValueIfFalseOptimizedFalse) falseInfoWhenTrue.setReachMode(FlowInfo.UNREACHABLE);
90             if (isValueIfTrueOptimizedTrue) trueInfoWhenFalse.setReachMode(FlowInfo.UNREACHABLE);
91             if (isValueIfFalseOptimizedTrue) falseInfoWhenFalse.setReachMode(FlowInfo.UNREACHABLE);
92
93             mergedInfo =
94                 FlowInfo.conditional(
95                     trueInfoWhenTrue.mergedWith(falseInfoWhenTrue),
96                     trueInfoWhenFalse.mergedWith(falseInfoWhenFalse));
97         }
98         mergedInitStateIndex =
99             currentScope.methodScope().recordInitializationStates(mergedInfo);
100         mergedInfo.setReachMode(mode);
101         return mergedInfo;
102     }
103
104     /**
105      * Code generation for the conditional operator ?:
106      *
107      * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
108      * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
109      * @param valueRequired boolean
110     */

111     public void generateCode(
112         BlockScope currentScope,
113         CodeStream codeStream,
114         boolean valueRequired) {
115
116         int pc = codeStream.position;
117         BranchLabel endifLabel, falseLabel;
118         if (constant != Constant.NotAConstant) {
119             if (valueRequired)
120                 codeStream.generateConstant(constant, implicitConversion);
121             codeStream.recordPositionsFrom(pc, this.sourceStart);
122             return;
123         }
124         Constant cst = condition.optimizedBooleanConstant();
125         boolean needTruePart = !(cst != Constant.NotAConstant && cst.booleanValue() == false);
126         boolean needFalsePart = !(cst != Constant.NotAConstant && cst.booleanValue() == true);
127         endifLabel = new BranchLabel(codeStream);
128
129         // Generate code for the condition
130
falseLabel = new BranchLabel(codeStream);
131         falseLabel.tagBits |= BranchLabel.USED;
132         condition.generateOptimizedBoolean(
133             currentScope,
134             codeStream,
135             null,
136             falseLabel,
137             cst == Constant.NotAConstant);
138
139         if (trueInitStateIndex != -1) {
140             codeStream.removeNotDefinitelyAssignedVariables(
141                 currentScope,
142                 trueInitStateIndex);
143             codeStream.addDefinitelyAssignedVariables(currentScope, trueInitStateIndex);
144         }
145         // Then code generation
146
if (needTruePart) {
147             valueIfTrue.generateCode(currentScope, codeStream, valueRequired);
148             if (needFalsePart) {
149                 // Jump over the else part
150
int position = codeStream.position;
151                 codeStream.goto_(endifLabel);
152                 codeStream.updateLastRecordedEndPC(currentScope, position);
153                 // Tune codestream stack size
154
if (valueRequired) {
155                     codeStream.decrStackSize(this.resolvedType == TypeBinding.LONG || this.resolvedType == TypeBinding.DOUBLE ? 2 : 1);
156                 }
157             }
158         }
159         if (needFalsePart) {
160             if (falseInitStateIndex != -1) {
161                 codeStream.removeNotDefinitelyAssignedVariables(
162                     currentScope,
163                     falseInitStateIndex);
164                 codeStream.addDefinitelyAssignedVariables(currentScope, falseInitStateIndex);
165             }
166             if (falseLabel.forwardReferenceCount() > 0) {
167                 falseLabel.place();
168             }
169             valueIfFalse.generateCode(currentScope, codeStream, valueRequired);
170             if (valueRequired) {
171                 codeStream.recordExpressionType(this.resolvedType);
172             }
173             if (needTruePart) {
174                 // End of if statement
175
endifLabel.place();
176             }
177         }
178         // May loose some local variable initializations : affecting the local variable attributes
179
if (mergedInitStateIndex != -1) {
180             codeStream.removeNotDefinitelyAssignedVariables(
181                 currentScope,
182                 mergedInitStateIndex);
183         }
184         // implicit conversion
185
if (valueRequired)
186             codeStream.generateImplicitConversion(implicitConversion);
187         codeStream.recordPositionsFrom(pc, this.sourceStart);
188     }
189
190     /**
191      * Optimized boolean code generation for the conditional operator ?:
192     */

193     public void generateOptimizedBoolean(
194         BlockScope currentScope,
195         CodeStream codeStream,
196         BranchLabel trueLabel,
197         BranchLabel falseLabel,
198         boolean valueRequired) {
199
200         if ((constant != Constant.NotAConstant) && (constant.typeID() == T_boolean) // constant
201
|| ((valueIfTrue.implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4) != T_boolean) { // non boolean values
202
super.generateOptimizedBoolean(currentScope, codeStream, trueLabel, falseLabel, valueRequired);
203             return;
204         }
205         Constant cst = condition.constant;
206         Constant condCst = condition.optimizedBooleanConstant();
207         boolean needTruePart =
208             !(((cst != Constant.NotAConstant) && (cst.booleanValue() == false))
209                 || ((condCst != Constant.NotAConstant) && (condCst.booleanValue() == false)));
210         boolean needFalsePart =
211             !(((cst != Constant.NotAConstant) && (cst.booleanValue() == true))
212                 || ((condCst != Constant.NotAConstant) && (condCst.booleanValue() == true)));
213
214         BranchLabel internalFalseLabel, endifLabel = new BranchLabel(codeStream);
215
216         // Generate code for the condition
217
boolean needConditionValue = (cst == Constant.NotAConstant) && (condCst == Constant.NotAConstant);
218         condition.generateOptimizedBoolean(
219                 currentScope,
220                 codeStream,
221                 null,
222                 internalFalseLabel = new BranchLabel(codeStream),
223                 needConditionValue);
224
225         if (trueInitStateIndex != -1) {
226             codeStream.removeNotDefinitelyAssignedVariables(
227                 currentScope,
228                 trueInitStateIndex);
229             codeStream.addDefinitelyAssignedVariables(currentScope, trueInitStateIndex);
230         }
231         // Then code generation
232
if (needTruePart) {
233             valueIfTrue.generateOptimizedBoolean(currentScope, codeStream, trueLabel, falseLabel, valueRequired);
234             
235             if (needFalsePart) {
236                 // Jump over the else part
237
JumpEndif: {
238                     if (falseLabel == null) {
239                         if (trueLabel != null) {
240                             // implicit falling through the FALSE case
241
cst = this.optimizedIfTrueConstant;
242                             boolean isValueIfTrueOptimizedTrue = cst != null && cst != Constant.NotAConstant && cst.booleanValue() == true;
243                             if (isValueIfTrueOptimizedTrue) break JumpEndif; // no need to jump over, since branched to true already
244
}
245                     } else {
246                         // implicit falling through the TRUE case
247
if (trueLabel == null) {
248                             cst = this.optimizedIfTrueConstant;
249                             boolean isValueIfTrueOptimizedFalse = cst != null && cst != Constant.NotAConstant && cst.booleanValue() == false;
250                             if (isValueIfTrueOptimizedFalse) break JumpEndif; // no need to jump over, since branched to false already
251
} else {
252                             // no implicit fall through TRUE/FALSE --> should never occur
253
}
254                     }
255                     int position = codeStream.position;
256                     codeStream.goto_(endifLabel);
257                     codeStream.updateLastRecordedEndPC(currentScope, position);
258                 }
259                 // No need to decrement codestream stack size
260
// since valueIfTrue was already consumed by branch bytecode
261
}
262         }
263         if (needFalsePart) {
264             internalFalseLabel.place();
265             if (falseInitStateIndex != -1) {
266                 codeStream.removeNotDefinitelyAssignedVariables(currentScope, falseInitStateIndex);
267                 codeStream.addDefinitelyAssignedVariables(currentScope, falseInitStateIndex);
268             }
269             valueIfFalse.generateOptimizedBoolean(currentScope, codeStream, trueLabel, falseLabel, valueRequired);
270
271             // End of if statement
272
endifLabel.place();
273         }
274         // May loose some local variable initializations : affecting the local variable attributes
275
if (mergedInitStateIndex != -1) {
276             codeStream.removeNotDefinitelyAssignedVariables(currentScope, mergedInitStateIndex);
277         }
278         // no implicit conversion for boolean values
279
codeStream.updateLastRecordedEndPC(currentScope, codeStream.position);
280     }
281     
282 public int nullStatus(FlowInfo flowInfo) {
283     Constant cst = this.condition.optimizedBooleanConstant();
284     if (cst != Constant.NotAConstant) {
285         if (cst.booleanValue()) {
286             return valueIfTrue.nullStatus(flowInfo);
287         }
288         return valueIfFalse.nullStatus(flowInfo);
289     }
290     int ifTrueNullStatus = valueIfTrue.nullStatus(flowInfo),
291         ifFalseNullStatus = valueIfFalse.nullStatus(flowInfo);
292     if (ifTrueNullStatus == ifFalseNullStatus) {
293         return ifTrueNullStatus;
294     }
295     return FlowInfo.UNKNOWN;
296     // cannot decide which branch to take, and they disagree
297
}
298
299     public Constant optimizedBooleanConstant() {
300
301         return this.optimizedBooleanConstant == null ? this.constant : this.optimizedBooleanConstant;
302     }
303     
304     public StringBuffer JavaDoc printExpressionNoParenthesis(int indent, StringBuffer JavaDoc output) {
305         
306         condition.printExpression(indent, output).append(" ? "); //$NON-NLS-1$
307
valueIfTrue.printExpression(0, output).append(" : "); //$NON-NLS-1$
308
return valueIfFalse.printExpression(0, output);
309     }
310
311     public TypeBinding resolveType(BlockScope scope) {
312         // JLS3 15.25
313
constant = Constant.NotAConstant;
314         LookupEnvironment env = scope.environment();
315         boolean use15specifics = scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5;
316         TypeBinding conditionType = condition.resolveTypeExpecting(scope, TypeBinding.BOOLEAN);
317         condition.computeConversion(scope, TypeBinding.BOOLEAN, conditionType);
318         
319         if (valueIfTrue instanceof CastExpression) valueIfTrue.bits |= DisableUnnecessaryCastCheck; // will check later on
320
TypeBinding originalValueIfTrueType = valueIfTrue.resolveType(scope);
321
322         if (valueIfFalse instanceof CastExpression) valueIfFalse.bits |= DisableUnnecessaryCastCheck; // will check later on
323
TypeBinding originalValueIfFalseType = valueIfFalse.resolveType(scope);
324
325         if (conditionType == null || originalValueIfTrueType == null || originalValueIfFalseType == null)
326             return null;
327
328         TypeBinding valueIfTrueType = originalValueIfTrueType;
329         TypeBinding valueIfFalseType = originalValueIfFalseType;
330         if (use15specifics && valueIfTrueType != valueIfFalseType) {
331             if (valueIfTrueType.isBaseType()) {
332                 if (valueIfFalseType.isBaseType()) {
333                     // bool ? baseType : baseType
334
if (valueIfTrueType == TypeBinding.NULL) { // bool ? null : 12 --> Integer
335
valueIfFalseType = env.computeBoxingType(valueIfFalseType); // boxing
336
} else if (valueIfFalseType == TypeBinding.NULL) { // bool ? 12 : null --> Integer
337
valueIfTrueType = env.computeBoxingType(valueIfTrueType); // boxing
338
}
339                 } else {
340                     // bool ? baseType : nonBaseType
341
TypeBinding unboxedIfFalseType = valueIfFalseType.isBaseType() ? valueIfFalseType : env.computeBoxingType(valueIfFalseType);
342                     if (valueIfTrueType.isNumericType() && unboxedIfFalseType.isNumericType()) {
343                         valueIfFalseType = unboxedIfFalseType; // unboxing
344
} else if (valueIfTrueType != TypeBinding.NULL) { // bool ? 12 : new Integer(12) --> int
345
valueIfFalseType = env.computeBoxingType(valueIfFalseType); // unboxing
346
}
347                 }
348             } else if (valueIfFalseType.isBaseType()) {
349                     // bool ? nonBaseType : baseType
350
TypeBinding unboxedIfTrueType = valueIfTrueType.isBaseType() ? valueIfTrueType : env.computeBoxingType(valueIfTrueType);
351                     if (unboxedIfTrueType.isNumericType() && valueIfFalseType.isNumericType()) {
352                         valueIfTrueType = unboxedIfTrueType; // unboxing
353
} else if (valueIfFalseType != TypeBinding.NULL) { // bool ? new Integer(12) : 12 --> int
354
valueIfTrueType = env.computeBoxingType(valueIfTrueType); // unboxing
355
}
356             } else {
357                     // bool ? nonBaseType : nonBaseType
358
TypeBinding unboxedIfTrueType = env.computeBoxingType(valueIfTrueType);
359                     TypeBinding unboxedIfFalseType = env.computeBoxingType(valueIfFalseType);
360                     if (unboxedIfTrueType.isNumericType() && unboxedIfFalseType.isNumericType()) {
361                         valueIfTrueType = unboxedIfTrueType;
362                         valueIfFalseType = unboxedIfFalseType;
363                     }
364             }
365         }
366         // Propagate the constant value from the valueIfTrue and valueIFFalse expression if it is possible
367
Constant condConstant, trueConstant, falseConstant;
368         if ((condConstant = condition.constant) != Constant.NotAConstant
369             && (trueConstant = valueIfTrue.constant) != Constant.NotAConstant
370             && (falseConstant = valueIfFalse.constant) != Constant.NotAConstant) {
371             // all terms are constant expression so we can propagate the constant
372
// from valueIFTrue or valueIfFalse to the receiver constant
373
constant = condConstant.booleanValue() ? trueConstant : falseConstant;
374         }
375         if (valueIfTrueType == valueIfFalseType) { // harmed the implicit conversion
376
valueIfTrue.computeConversion(scope, valueIfTrueType, originalValueIfTrueType);
377             valueIfFalse.computeConversion(scope, valueIfFalseType, originalValueIfFalseType);
378             if (valueIfTrueType == TypeBinding.BOOLEAN) {
379                 this.optimizedIfTrueConstant = valueIfTrue.optimizedBooleanConstant();
380                 this.optimizedIfFalseConstant = valueIfFalse.optimizedBooleanConstant();
381                 if (this.optimizedIfTrueConstant != Constant.NotAConstant
382                         && this.optimizedIfFalseConstant != Constant.NotAConstant
383                         && this.optimizedIfTrueConstant.booleanValue() == this.optimizedIfFalseConstant.booleanValue()) {
384                     // a ? true : true / a ? false : false
385
this.optimizedBooleanConstant = optimizedIfTrueConstant;
386                 } else if ((condConstant = condition.optimizedBooleanConstant()) != Constant.NotAConstant) { // Propagate the optimized boolean constant if possible
387
this.optimizedBooleanConstant = condConstant.booleanValue()
388                         ? this.optimizedIfTrueConstant
389                         : this.optimizedIfFalseConstant;
390                 }
391             }
392             return this.resolvedType = valueIfTrueType;
393         }
394         // Determine the return type depending on argument types
395
// Numeric types
396
if (valueIfTrueType.isNumericType() && valueIfFalseType.isNumericType()) {
397             // (Short x Byte) or (Byte x Short)"
398
if ((valueIfTrueType == TypeBinding.BYTE && valueIfFalseType == TypeBinding.SHORT)
399                 || (valueIfTrueType == TypeBinding.SHORT && valueIfFalseType == TypeBinding.BYTE)) {
400                 valueIfTrue.computeConversion(scope, TypeBinding.SHORT, originalValueIfTrueType);
401                 valueIfFalse.computeConversion(scope, TypeBinding.SHORT, originalValueIfFalseType);
402                 return this.resolvedType = TypeBinding.SHORT;
403             }
404             // <Byte|Short|Char> x constant(Int) ---> <Byte|Short|Char> and reciprocally
405
if ((valueIfTrueType == TypeBinding.BYTE || valueIfTrueType == TypeBinding.SHORT || valueIfTrueType == TypeBinding.CHAR)
406                     && (valueIfFalseType == TypeBinding.INT
407                         && valueIfFalse.isConstantValueOfTypeAssignableToType(valueIfFalseType, valueIfTrueType))) {
408                 valueIfTrue.computeConversion(scope, valueIfTrueType, originalValueIfTrueType);
409                 valueIfFalse.computeConversion(scope, valueIfTrueType, originalValueIfFalseType);
410                 return this.resolvedType = valueIfTrueType;
411             }
412             if ((valueIfFalseType == TypeBinding.BYTE
413                     || valueIfFalseType == TypeBinding.SHORT
414                     || valueIfFalseType == TypeBinding.CHAR)
415                     && (valueIfTrueType == TypeBinding.INT
416                         && valueIfTrue.isConstantValueOfTypeAssignableToType(valueIfTrueType, valueIfFalseType))) {
417                 valueIfTrue.computeConversion(scope, valueIfFalseType, originalValueIfTrueType);
418                 valueIfFalse.computeConversion(scope, valueIfFalseType, originalValueIfFalseType);
419                 return this.resolvedType = valueIfFalseType;
420             }
421             // Manual binary numeric promotion
422
// int
423
if (BaseTypeBinding.isNarrowing(valueIfTrueType.id, T_int)
424                     && BaseTypeBinding.isNarrowing(valueIfFalseType.id, T_int)) {
425                 valueIfTrue.computeConversion(scope, TypeBinding.INT, originalValueIfTrueType);
426                 valueIfFalse.computeConversion(scope, TypeBinding.INT, originalValueIfFalseType);
427                 return this.resolvedType = TypeBinding.INT;
428             }
429             // long
430
if (BaseTypeBinding.isNarrowing(valueIfTrueType.id, T_long)
431                     && BaseTypeBinding.isNarrowing(valueIfFalseType.id, T_long)) {
432                 valueIfTrue.computeConversion(scope, TypeBinding.LONG, originalValueIfTrueType);
433                 valueIfFalse.computeConversion(scope, TypeBinding.LONG, originalValueIfFalseType);
434                 return this.resolvedType = TypeBinding.LONG;
435             }
436             // float
437
if (BaseTypeBinding.isNarrowing(valueIfTrueType.id, T_float)
438                     && BaseTypeBinding.isNarrowing(valueIfFalseType.id, T_float)) {
439                 valueIfTrue.computeConversion(scope, TypeBinding.FLOAT, originalValueIfTrueType);
440                 valueIfFalse.computeConversion(scope, TypeBinding.FLOAT, originalValueIfFalseType);
441                 return this.resolvedType = TypeBinding.FLOAT;
442             }
443             // double
444
valueIfTrue.computeConversion(scope, TypeBinding.DOUBLE, originalValueIfTrueType);
445             valueIfFalse.computeConversion(scope, TypeBinding.DOUBLE, originalValueIfFalseType);
446             return this.resolvedType = TypeBinding.DOUBLE;
447         }
448         // Type references (null null is already tested)
449
if (valueIfTrueType.isBaseType() && valueIfTrueType != TypeBinding.NULL) {
450             if (use15specifics) {
451                 valueIfTrueType = env.computeBoxingType(valueIfTrueType);
452             } else {
453                 scope.problemReporter().conditionalArgumentsIncompatibleTypes(this, valueIfTrueType, valueIfFalseType);
454                 return null;
455             }
456         }
457         if (valueIfFalseType.isBaseType() && valueIfFalseType != TypeBinding.NULL) {
458             if (use15specifics) {
459                 valueIfFalseType = env.computeBoxingType(valueIfFalseType);
460             } else {
461                 scope.problemReporter().conditionalArgumentsIncompatibleTypes(this, valueIfTrueType, valueIfFalseType);
462                 return null;
463             }
464         }
465         if (use15specifics) {
466             // >= 1.5 : LUB(operand types) must exist
467
TypeBinding commonType = null;
468             if (valueIfTrueType == TypeBinding.NULL) {
469                 commonType = valueIfFalseType;
470             } else if (valueIfFalseType == TypeBinding.NULL) {
471                 commonType = valueIfTrueType;
472             } else {
473                 commonType = scope.lowerUpperBound(new TypeBinding[] { valueIfTrueType, valueIfFalseType });
474             }
475             if (commonType != null) {
476                 valueIfTrue.computeConversion(scope, commonType, originalValueIfTrueType);
477                 valueIfFalse.computeConversion(scope, commonType, originalValueIfFalseType);
478                 return this.resolvedType = commonType.capture(scope, this.sourceEnd);
479             }
480         } else {
481             // < 1.5 : one operand must be convertible to the other
482
if (valueIfFalseType.isCompatibleWith(valueIfTrueType)) {
483                 valueIfTrue.computeConversion(scope, valueIfTrueType, originalValueIfTrueType);
484                 valueIfFalse.computeConversion(scope, valueIfTrueType, originalValueIfFalseType);
485                 return this.resolvedType = valueIfTrueType;
486             } else if (valueIfTrueType.isCompatibleWith(valueIfFalseType)) {
487                 valueIfTrue.computeConversion(scope, valueIfFalseType, originalValueIfTrueType);
488                 valueIfFalse.computeConversion(scope, valueIfFalseType, originalValueIfFalseType);
489                 return this.resolvedType = valueIfFalseType;
490             }
491         }
492         scope.problemReporter().conditionalArgumentsIncompatibleTypes(
493             this,
494             valueIfTrueType,
495             valueIfFalseType);
496         return null;
497     }
498     
499     public void traverse(ASTVisitor visitor, BlockScope scope) {
500         if (visitor.visit(this, scope)) {
501             condition.traverse(visitor, scope);
502             valueIfTrue.traverse(visitor, scope);
503             valueIfFalse.traverse(visitor, scope);
504         }
505         visitor.endVisit(this, scope);
506     }
507 }
508
Popular Tags