001: /*******************************************************************************
002: * Copyright (c) 2000, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.jdt.internal.compiler.ast;
011:
012: import org.eclipse.jdt.internal.compiler.ASTVisitor;
013: import org.eclipse.jdt.internal.compiler.impl.*;
014: import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
015: import org.eclipse.jdt.internal.compiler.codegen.*;
016: import org.eclipse.jdt.internal.compiler.flow.*;
017: import org.eclipse.jdt.internal.compiler.lookup.*;
018:
019: public class ConditionalExpression extends OperatorExpression {
020:
021: public Expression condition, valueIfTrue, valueIfFalse;
022: public Constant optimizedBooleanConstant;
023: public Constant optimizedIfTrueConstant;
024: public Constant optimizedIfFalseConstant;
025:
026: // for local variables table attributes
027: int trueInitStateIndex = -1;
028: int falseInitStateIndex = -1;
029: int mergedInitStateIndex = -1;
030:
031: public ConditionalExpression(Expression condition,
032: Expression valueIfTrue, Expression valueIfFalse) {
033: this .condition = condition;
034: this .valueIfTrue = valueIfTrue;
035: this .valueIfFalse = valueIfFalse;
036: sourceStart = condition.sourceStart;
037: sourceEnd = valueIfFalse.sourceEnd;
038: }
039:
040: public FlowInfo analyseCode(BlockScope currentScope,
041: FlowContext flowContext, FlowInfo flowInfo) {
042: Constant cst = this .condition.optimizedBooleanConstant();
043: boolean isConditionOptimizedTrue = cst != Constant.NotAConstant
044: && cst.booleanValue() == true;
045: boolean isConditionOptimizedFalse = cst != Constant.NotAConstant
046: && cst.booleanValue() == false;
047:
048: int mode = flowInfo.reachMode();
049: flowInfo = condition.analyseCode(currentScope, flowContext,
050: flowInfo, cst == Constant.NotAConstant);
051:
052: // process the if-true part
053: FlowInfo trueFlowInfo = flowInfo.initsWhenTrue().copy();
054: if (isConditionOptimizedFalse) {
055: trueFlowInfo.setReachMode(FlowInfo.UNREACHABLE);
056: }
057: trueInitStateIndex = currentScope.methodScope()
058: .recordInitializationStates(trueFlowInfo);
059: trueFlowInfo = valueIfTrue.analyseCode(currentScope,
060: flowContext, trueFlowInfo);
061:
062: // process the if-false part
063: FlowInfo falseFlowInfo = flowInfo.initsWhenFalse().copy();
064: if (isConditionOptimizedTrue) {
065: falseFlowInfo.setReachMode(FlowInfo.UNREACHABLE);
066: }
067: falseInitStateIndex = currentScope.methodScope()
068: .recordInitializationStates(falseFlowInfo);
069: falseFlowInfo = valueIfFalse.analyseCode(currentScope,
070: flowContext, falseFlowInfo);
071:
072: // merge if-true & if-false initializations
073: FlowInfo mergedInfo;
074: if (isConditionOptimizedTrue) {
075: mergedInfo = trueFlowInfo
076: .addPotentialInitializationsFrom(falseFlowInfo);
077: } else if (isConditionOptimizedFalse) {
078: mergedInfo = falseFlowInfo
079: .addPotentialInitializationsFrom(trueFlowInfo);
080: } else {
081: // if ((t && (v = t)) ? t : t && (v = f)) r = v; -- ok
082: cst = this .optimizedIfTrueConstant;
083: boolean isValueIfTrueOptimizedTrue = cst != null
084: && cst != Constant.NotAConstant
085: && cst.booleanValue() == true;
086: boolean isValueIfTrueOptimizedFalse = cst != null
087: && cst != Constant.NotAConstant
088: && cst.booleanValue() == false;
089:
090: cst = this .optimizedIfFalseConstant;
091: boolean isValueIfFalseOptimizedTrue = cst != null
092: && cst != Constant.NotAConstant
093: && cst.booleanValue() == true;
094: boolean isValueIfFalseOptimizedFalse = cst != null
095: && cst != Constant.NotAConstant
096: && cst.booleanValue() == false;
097:
098: UnconditionalFlowInfo trueInfoWhenTrue = trueFlowInfo
099: .initsWhenTrue().unconditionalCopy();
100: UnconditionalFlowInfo falseInfoWhenTrue = falseFlowInfo
101: .initsWhenTrue().unconditionalCopy();
102: UnconditionalFlowInfo trueInfoWhenFalse = trueFlowInfo
103: .initsWhenFalse().unconditionalInits();
104: UnconditionalFlowInfo falseInfoWhenFalse = falseFlowInfo
105: .initsWhenFalse().unconditionalInits();
106: if (isValueIfTrueOptimizedFalse)
107: trueInfoWhenTrue.setReachMode(FlowInfo.UNREACHABLE);
108: if (isValueIfFalseOptimizedFalse)
109: falseInfoWhenTrue.setReachMode(FlowInfo.UNREACHABLE);
110: if (isValueIfTrueOptimizedTrue)
111: trueInfoWhenFalse.setReachMode(FlowInfo.UNREACHABLE);
112: if (isValueIfFalseOptimizedTrue)
113: falseInfoWhenFalse.setReachMode(FlowInfo.UNREACHABLE);
114:
115: mergedInfo = FlowInfo.conditional(trueInfoWhenTrue
116: .mergedWith(falseInfoWhenTrue), trueInfoWhenFalse
117: .mergedWith(falseInfoWhenFalse));
118: }
119: mergedInitStateIndex = currentScope.methodScope()
120: .recordInitializationStates(mergedInfo);
121: mergedInfo.setReachMode(mode);
122: return mergedInfo;
123: }
124:
125: /**
126: * Code generation for the conditional operator ?:
127: *
128: * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
129: * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
130: * @param valueRequired boolean
131: */
132: public void generateCode(BlockScope currentScope,
133: CodeStream codeStream, boolean valueRequired) {
134:
135: int pc = codeStream.position;
136: BranchLabel endifLabel, falseLabel;
137: if (constant != Constant.NotAConstant) {
138: if (valueRequired)
139: codeStream.generateConstant(constant,
140: implicitConversion);
141: codeStream.recordPositionsFrom(pc, this .sourceStart);
142: return;
143: }
144: Constant cst = condition.optimizedBooleanConstant();
145: boolean needTruePart = !(cst != Constant.NotAConstant && cst
146: .booleanValue() == false);
147: boolean needFalsePart = !(cst != Constant.NotAConstant && cst
148: .booleanValue() == true);
149: endifLabel = new BranchLabel(codeStream);
150:
151: // Generate code for the condition
152: falseLabel = new BranchLabel(codeStream);
153: falseLabel.tagBits |= BranchLabel.USED;
154: condition.generateOptimizedBoolean(currentScope, codeStream,
155: null, falseLabel, cst == Constant.NotAConstant);
156:
157: if (trueInitStateIndex != -1) {
158: codeStream.removeNotDefinitelyAssignedVariables(
159: currentScope, trueInitStateIndex);
160: codeStream.addDefinitelyAssignedVariables(currentScope,
161: trueInitStateIndex);
162: }
163: // Then code generation
164: if (needTruePart) {
165: valueIfTrue.generateCode(currentScope, codeStream,
166: valueRequired);
167: if (needFalsePart) {
168: // Jump over the else part
169: int position = codeStream.position;
170: codeStream.goto_(endifLabel);
171: codeStream.updateLastRecordedEndPC(currentScope,
172: position);
173: // Tune codestream stack size
174: if (valueRequired) {
175: codeStream
176: .decrStackSize(this .resolvedType == TypeBinding.LONG
177: || this .resolvedType == TypeBinding.DOUBLE ? 2
178: : 1);
179: }
180: }
181: }
182: if (needFalsePart) {
183: if (falseInitStateIndex != -1) {
184: codeStream.removeNotDefinitelyAssignedVariables(
185: currentScope, falseInitStateIndex);
186: codeStream.addDefinitelyAssignedVariables(currentScope,
187: falseInitStateIndex);
188: }
189: if (falseLabel.forwardReferenceCount() > 0) {
190: falseLabel.place();
191: }
192: valueIfFalse.generateCode(currentScope, codeStream,
193: valueRequired);
194: if (valueRequired) {
195: codeStream.recordExpressionType(this .resolvedType);
196: }
197: if (needTruePart) {
198: // End of if statement
199: endifLabel.place();
200: }
201: }
202: // May loose some local variable initializations : affecting the local variable attributes
203: if (mergedInitStateIndex != -1) {
204: codeStream.removeNotDefinitelyAssignedVariables(
205: currentScope, mergedInitStateIndex);
206: }
207: // implicit conversion
208: if (valueRequired)
209: codeStream.generateImplicitConversion(implicitConversion);
210: codeStream.recordPositionsFrom(pc, this .sourceStart);
211: }
212:
213: /**
214: * Optimized boolean code generation for the conditional operator ?:
215: */
216: public void generateOptimizedBoolean(BlockScope currentScope,
217: CodeStream codeStream, BranchLabel trueLabel,
218: BranchLabel falseLabel, boolean valueRequired) {
219:
220: if ((constant != Constant.NotAConstant)
221: && (constant.typeID() == T_boolean) // constant
222: || ((valueIfTrue.implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4) != T_boolean) { // non boolean values
223: super .generateOptimizedBoolean(currentScope, codeStream,
224: trueLabel, falseLabel, valueRequired);
225: return;
226: }
227: Constant cst = condition.constant;
228: Constant condCst = condition.optimizedBooleanConstant();
229: boolean needTruePart = !(((cst != Constant.NotAConstant) && (cst
230: .booleanValue() == false)) || ((condCst != Constant.NotAConstant) && (condCst
231: .booleanValue() == false)));
232: boolean needFalsePart = !(((cst != Constant.NotAConstant) && (cst
233: .booleanValue() == true)) || ((condCst != Constant.NotAConstant) && (condCst
234: .booleanValue() == true)));
235:
236: BranchLabel internalFalseLabel, endifLabel = new BranchLabel(
237: codeStream);
238:
239: // Generate code for the condition
240: boolean needConditionValue = (cst == Constant.NotAConstant)
241: && (condCst == Constant.NotAConstant);
242: condition.generateOptimizedBoolean(currentScope, codeStream,
243: null, internalFalseLabel = new BranchLabel(codeStream),
244: needConditionValue);
245:
246: if (trueInitStateIndex != -1) {
247: codeStream.removeNotDefinitelyAssignedVariables(
248: currentScope, trueInitStateIndex);
249: codeStream.addDefinitelyAssignedVariables(currentScope,
250: trueInitStateIndex);
251: }
252: // Then code generation
253: if (needTruePart) {
254: valueIfTrue.generateOptimizedBoolean(currentScope,
255: codeStream, trueLabel, falseLabel, valueRequired);
256:
257: if (needFalsePart) {
258: // Jump over the else part
259: JumpEndif: {
260: if (falseLabel == null) {
261: if (trueLabel != null) {
262: // implicit falling through the FALSE case
263: cst = this .optimizedIfTrueConstant;
264: boolean isValueIfTrueOptimizedTrue = cst != null
265: && cst != Constant.NotAConstant
266: && cst.booleanValue() == true;
267: if (isValueIfTrueOptimizedTrue)
268: break JumpEndif; // no need to jump over, since branched to true already
269: }
270: } else {
271: // implicit falling through the TRUE case
272: if (trueLabel == null) {
273: cst = this .optimizedIfTrueConstant;
274: boolean isValueIfTrueOptimizedFalse = cst != null
275: && cst != Constant.NotAConstant
276: && cst.booleanValue() == false;
277: if (isValueIfTrueOptimizedFalse)
278: break JumpEndif; // no need to jump over, since branched to false already
279: } else {
280: // no implicit fall through TRUE/FALSE --> should never occur
281: }
282: }
283: int position = codeStream.position;
284: codeStream.goto_(endifLabel);
285: codeStream.updateLastRecordedEndPC(currentScope,
286: position);
287: }
288: // No need to decrement codestream stack size
289: // since valueIfTrue was already consumed by branch bytecode
290: }
291: }
292: if (needFalsePart) {
293: internalFalseLabel.place();
294: if (falseInitStateIndex != -1) {
295: codeStream.removeNotDefinitelyAssignedVariables(
296: currentScope, falseInitStateIndex);
297: codeStream.addDefinitelyAssignedVariables(currentScope,
298: falseInitStateIndex);
299: }
300: valueIfFalse.generateOptimizedBoolean(currentScope,
301: codeStream, trueLabel, falseLabel, valueRequired);
302:
303: // End of if statement
304: endifLabel.place();
305: }
306: // May loose some local variable initializations : affecting the local variable attributes
307: if (mergedInitStateIndex != -1) {
308: codeStream.removeNotDefinitelyAssignedVariables(
309: currentScope, mergedInitStateIndex);
310: }
311: // no implicit conversion for boolean values
312: codeStream.updateLastRecordedEndPC(currentScope,
313: codeStream.position);
314: }
315:
316: public int nullStatus(FlowInfo flowInfo) {
317: Constant cst = this .condition.optimizedBooleanConstant();
318: if (cst != Constant.NotAConstant) {
319: if (cst.booleanValue()) {
320: return valueIfTrue.nullStatus(flowInfo);
321: }
322: return valueIfFalse.nullStatus(flowInfo);
323: }
324: int ifTrueNullStatus = valueIfTrue.nullStatus(flowInfo), ifFalseNullStatus = valueIfFalse
325: .nullStatus(flowInfo);
326: if (ifTrueNullStatus == ifFalseNullStatus) {
327: return ifTrueNullStatus;
328: }
329: return FlowInfo.UNKNOWN;
330: // cannot decide which branch to take, and they disagree
331: }
332:
333: public Constant optimizedBooleanConstant() {
334:
335: return this .optimizedBooleanConstant == null ? this .constant
336: : this .optimizedBooleanConstant;
337: }
338:
339: public StringBuffer printExpressionNoParenthesis(int indent,
340: StringBuffer output) {
341:
342: condition.printExpression(indent, output).append(" ? "); //$NON-NLS-1$
343: valueIfTrue.printExpression(0, output).append(" : "); //$NON-NLS-1$
344: return valueIfFalse.printExpression(0, output);
345: }
346:
347: public TypeBinding resolveType(BlockScope scope) {
348: // JLS3 15.25
349: constant = Constant.NotAConstant;
350: LookupEnvironment env = scope.environment();
351: boolean use15specifics = scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5;
352: TypeBinding conditionType = condition.resolveTypeExpecting(
353: scope, TypeBinding.BOOLEAN);
354: condition.computeConversion(scope, TypeBinding.BOOLEAN,
355: conditionType);
356:
357: if (valueIfTrue instanceof CastExpression)
358: valueIfTrue.bits |= DisableUnnecessaryCastCheck; // will check later on
359: TypeBinding originalValueIfTrueType = valueIfTrue
360: .resolveType(scope);
361:
362: if (valueIfFalse instanceof CastExpression)
363: valueIfFalse.bits |= DisableUnnecessaryCastCheck; // will check later on
364: TypeBinding originalValueIfFalseType = valueIfFalse
365: .resolveType(scope);
366:
367: if (conditionType == null || originalValueIfTrueType == null
368: || originalValueIfFalseType == null)
369: return null;
370:
371: TypeBinding valueIfTrueType = originalValueIfTrueType;
372: TypeBinding valueIfFalseType = originalValueIfFalseType;
373: if (use15specifics && valueIfTrueType != valueIfFalseType) {
374: if (valueIfTrueType.isBaseType()) {
375: if (valueIfFalseType.isBaseType()) {
376: // bool ? baseType : baseType
377: if (valueIfTrueType == TypeBinding.NULL) { // bool ? null : 12 --> Integer
378: valueIfFalseType = env
379: .computeBoxingType(valueIfFalseType); // boxing
380: } else if (valueIfFalseType == TypeBinding.NULL) { // bool ? 12 : null --> Integer
381: valueIfTrueType = env
382: .computeBoxingType(valueIfTrueType); // boxing
383: }
384: } else {
385: // bool ? baseType : nonBaseType
386: TypeBinding unboxedIfFalseType = valueIfFalseType
387: .isBaseType() ? valueIfFalseType : env
388: .computeBoxingType(valueIfFalseType);
389: if (valueIfTrueType.isNumericType()
390: && unboxedIfFalseType.isNumericType()) {
391: valueIfFalseType = unboxedIfFalseType; // unboxing
392: } else if (valueIfTrueType != TypeBinding.NULL) { // bool ? 12 : new Integer(12) --> int
393: valueIfFalseType = env
394: .computeBoxingType(valueIfFalseType); // unboxing
395: }
396: }
397: } else if (valueIfFalseType.isBaseType()) {
398: // bool ? nonBaseType : baseType
399: TypeBinding unboxedIfTrueType = valueIfTrueType
400: .isBaseType() ? valueIfTrueType : env
401: .computeBoxingType(valueIfTrueType);
402: if (unboxedIfTrueType.isNumericType()
403: && valueIfFalseType.isNumericType()) {
404: valueIfTrueType = unboxedIfTrueType; // unboxing
405: } else if (valueIfFalseType != TypeBinding.NULL) { // bool ? new Integer(12) : 12 --> int
406: valueIfTrueType = env
407: .computeBoxingType(valueIfTrueType); // unboxing
408: }
409: } else {
410: // bool ? nonBaseType : nonBaseType
411: TypeBinding unboxedIfTrueType = env
412: .computeBoxingType(valueIfTrueType);
413: TypeBinding unboxedIfFalseType = env
414: .computeBoxingType(valueIfFalseType);
415: if (unboxedIfTrueType.isNumericType()
416: && unboxedIfFalseType.isNumericType()) {
417: valueIfTrueType = unboxedIfTrueType;
418: valueIfFalseType = unboxedIfFalseType;
419: }
420: }
421: }
422: // Propagate the constant value from the valueIfTrue and valueIFFalse expression if it is possible
423: Constant condConstant, trueConstant, falseConstant;
424: if ((condConstant = condition.constant) != Constant.NotAConstant
425: && (trueConstant = valueIfTrue.constant) != Constant.NotAConstant
426: && (falseConstant = valueIfFalse.constant) != Constant.NotAConstant) {
427: // all terms are constant expression so we can propagate the constant
428: // from valueIFTrue or valueIfFalse to the receiver constant
429: constant = condConstant.booleanValue() ? trueConstant
430: : falseConstant;
431: }
432: if (valueIfTrueType == valueIfFalseType) { // harmed the implicit conversion
433: valueIfTrue.computeConversion(scope, valueIfTrueType,
434: originalValueIfTrueType);
435: valueIfFalse.computeConversion(scope, valueIfFalseType,
436: originalValueIfFalseType);
437: if (valueIfTrueType == TypeBinding.BOOLEAN) {
438: this .optimizedIfTrueConstant = valueIfTrue
439: .optimizedBooleanConstant();
440: this .optimizedIfFalseConstant = valueIfFalse
441: .optimizedBooleanConstant();
442: if (this .optimizedIfTrueConstant != Constant.NotAConstant
443: && this .optimizedIfFalseConstant != Constant.NotAConstant
444: && this .optimizedIfTrueConstant.booleanValue() == this .optimizedIfFalseConstant
445: .booleanValue()) {
446: // a ? true : true / a ? false : false
447: this .optimizedBooleanConstant = optimizedIfTrueConstant;
448: } else if ((condConstant = condition
449: .optimizedBooleanConstant()) != Constant.NotAConstant) { // Propagate the optimized boolean constant if possible
450: this .optimizedBooleanConstant = condConstant
451: .booleanValue() ? this .optimizedIfTrueConstant
452: : this .optimizedIfFalseConstant;
453: }
454: }
455: return this .resolvedType = valueIfTrueType;
456: }
457: // Determine the return type depending on argument types
458: // Numeric types
459: if (valueIfTrueType.isNumericType()
460: && valueIfFalseType.isNumericType()) {
461: // (Short x Byte) or (Byte x Short)"
462: if ((valueIfTrueType == TypeBinding.BYTE && valueIfFalseType == TypeBinding.SHORT)
463: || (valueIfTrueType == TypeBinding.SHORT && valueIfFalseType == TypeBinding.BYTE)) {
464: valueIfTrue.computeConversion(scope, TypeBinding.SHORT,
465: originalValueIfTrueType);
466: valueIfFalse.computeConversion(scope,
467: TypeBinding.SHORT, originalValueIfFalseType);
468: return this .resolvedType = TypeBinding.SHORT;
469: }
470: // <Byte|Short|Char> x constant(Int) ---> <Byte|Short|Char> and reciprocally
471: if ((valueIfTrueType == TypeBinding.BYTE
472: || valueIfTrueType == TypeBinding.SHORT || valueIfTrueType == TypeBinding.CHAR)
473: && (valueIfFalseType == TypeBinding.INT && valueIfFalse
474: .isConstantValueOfTypeAssignableToType(
475: valueIfFalseType, valueIfTrueType))) {
476: valueIfTrue.computeConversion(scope, valueIfTrueType,
477: originalValueIfTrueType);
478: valueIfFalse.computeConversion(scope, valueIfTrueType,
479: originalValueIfFalseType);
480: return this .resolvedType = valueIfTrueType;
481: }
482: if ((valueIfFalseType == TypeBinding.BYTE
483: || valueIfFalseType == TypeBinding.SHORT || valueIfFalseType == TypeBinding.CHAR)
484: && (valueIfTrueType == TypeBinding.INT && valueIfTrue
485: .isConstantValueOfTypeAssignableToType(
486: valueIfTrueType, valueIfFalseType))) {
487: valueIfTrue.computeConversion(scope, valueIfFalseType,
488: originalValueIfTrueType);
489: valueIfFalse.computeConversion(scope, valueIfFalseType,
490: originalValueIfFalseType);
491: return this .resolvedType = valueIfFalseType;
492: }
493: // Manual binary numeric promotion
494: // int
495: if (BaseTypeBinding.isNarrowing(valueIfTrueType.id, T_int)
496: && BaseTypeBinding.isNarrowing(valueIfFalseType.id,
497: T_int)) {
498: valueIfTrue.computeConversion(scope, TypeBinding.INT,
499: originalValueIfTrueType);
500: valueIfFalse.computeConversion(scope, TypeBinding.INT,
501: originalValueIfFalseType);
502: return this .resolvedType = TypeBinding.INT;
503: }
504: // long
505: if (BaseTypeBinding.isNarrowing(valueIfTrueType.id, T_long)
506: && BaseTypeBinding.isNarrowing(valueIfFalseType.id,
507: T_long)) {
508: valueIfTrue.computeConversion(scope, TypeBinding.LONG,
509: originalValueIfTrueType);
510: valueIfFalse.computeConversion(scope, TypeBinding.LONG,
511: originalValueIfFalseType);
512: return this .resolvedType = TypeBinding.LONG;
513: }
514: // float
515: if (BaseTypeBinding
516: .isNarrowing(valueIfTrueType.id, T_float)
517: && BaseTypeBinding.isNarrowing(valueIfFalseType.id,
518: T_float)) {
519: valueIfTrue.computeConversion(scope, TypeBinding.FLOAT,
520: originalValueIfTrueType);
521: valueIfFalse.computeConversion(scope,
522: TypeBinding.FLOAT, originalValueIfFalseType);
523: return this .resolvedType = TypeBinding.FLOAT;
524: }
525: // double
526: valueIfTrue.computeConversion(scope, TypeBinding.DOUBLE,
527: originalValueIfTrueType);
528: valueIfFalse.computeConversion(scope, TypeBinding.DOUBLE,
529: originalValueIfFalseType);
530: return this .resolvedType = TypeBinding.DOUBLE;
531: }
532: // Type references (null null is already tested)
533: if (valueIfTrueType.isBaseType()
534: && valueIfTrueType != TypeBinding.NULL) {
535: if (use15specifics) {
536: valueIfTrueType = env
537: .computeBoxingType(valueIfTrueType);
538: } else {
539: scope.problemReporter()
540: .conditionalArgumentsIncompatibleTypes(this ,
541: valueIfTrueType, valueIfFalseType);
542: return null;
543: }
544: }
545: if (valueIfFalseType.isBaseType()
546: && valueIfFalseType != TypeBinding.NULL) {
547: if (use15specifics) {
548: valueIfFalseType = env
549: .computeBoxingType(valueIfFalseType);
550: } else {
551: scope.problemReporter()
552: .conditionalArgumentsIncompatibleTypes(this ,
553: valueIfTrueType, valueIfFalseType);
554: return null;
555: }
556: }
557: if (use15specifics) {
558: // >= 1.5 : LUB(operand types) must exist
559: TypeBinding commonType = null;
560: if (valueIfTrueType == TypeBinding.NULL) {
561: commonType = valueIfFalseType;
562: } else if (valueIfFalseType == TypeBinding.NULL) {
563: commonType = valueIfTrueType;
564: } else {
565: commonType = scope.lowerUpperBound(new TypeBinding[] {
566: valueIfTrueType, valueIfFalseType });
567: }
568: if (commonType != null) {
569: valueIfTrue.computeConversion(scope, commonType,
570: originalValueIfTrueType);
571: valueIfFalse.computeConversion(scope, commonType,
572: originalValueIfFalseType);
573: return this .resolvedType = commonType.capture(scope,
574: this .sourceEnd);
575: }
576: } else {
577: // < 1.5 : one operand must be convertible to the other
578: if (valueIfFalseType.isCompatibleWith(valueIfTrueType)) {
579: valueIfTrue.computeConversion(scope, valueIfTrueType,
580: originalValueIfTrueType);
581: valueIfFalse.computeConversion(scope, valueIfTrueType,
582: originalValueIfFalseType);
583: return this .resolvedType = valueIfTrueType;
584: } else if (valueIfTrueType
585: .isCompatibleWith(valueIfFalseType)) {
586: valueIfTrue.computeConversion(scope, valueIfFalseType,
587: originalValueIfTrueType);
588: valueIfFalse.computeConversion(scope, valueIfFalseType,
589: originalValueIfFalseType);
590: return this .resolvedType = valueIfFalseType;
591: }
592: }
593: scope.problemReporter().conditionalArgumentsIncompatibleTypes(
594: this , valueIfTrueType, valueIfFalseType);
595: return null;
596: }
597:
598: public void traverse(ASTVisitor visitor, BlockScope scope) {
599: if (visitor.visit(this, scope)) {
600: condition.traverse(visitor, scope);
601: valueIfTrue.traverse(visitor, scope);
602: valueIfFalse.traverse(visitor, scope);
603: }
604: visitor.endVisit(this, scope);
605: }
606: }
|