Index: compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java,v --- compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java 30 Oct 2006 17:27:23 -0000 1.107 +++ compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java 22 Nov 2006 14:17:46 -0000 @@ -352,12 +352,18 @@ ReferenceBinding interfaceType = (ReferenceBinding) expressionType; match = interfaceType.findSuperTypeWithSameErasure(castType); if (match != null) { - return checkUnsafeCast(scope, castType, interfaceType, match, false); + if (use15specifics) { + return checkUnsafeCast(scope, castType, interfaceType, match, false); + } + return true; } tagAsNeedCheckCast(); match = castType.findSuperTypeWithSameErasure(interfaceType); if (match != null) { - return checkUnsafeCast(scope, castType, interfaceType, match, true); + if (use15specifics) { + return checkUnsafeCast(scope, castType, interfaceType, match, true); + } + return true; } if (use15specifics) { checkUnsafeCast(scope, castType, expressionType, null /*no match*/, true); @@ -387,29 +393,35 @@ tagAsUnnecessaryCast(scope, castType); return true; } - if (((ReferenceBinding) castType).isFinal()) { - // no subclass for castType, thus compile-time check is valid - match = castType.findSuperTypeWithSameErasure(expressionType); - if (match == null) { - return false; + // can only be a downcast + tagAsNeedCheckCast(); + match = castType.findSuperTypeWithSameErasure(expressionType); + if (match != null) { + if (use15specifics) { + return checkUnsafeCast(scope, castType, expressionType, match, true); } + return true; + } + if (((ReferenceBinding) castType).isFinal()) { + // no subclass for castType, thus compile-time check is invalid + return false; } if (use15specifics) { + checkUnsafeCast(scope, castType, expressionType, null /*no match*/, true); // ensure there is no collision between both interfaces: i.e. I1 extends List, I2 extends List if (((ReferenceBinding)castType).hasIncompatibleSuperType((ReferenceBinding) expressionType)) { return false; } } + return true; } } - tagAsNeedCheckCast(); - return true; } else { switch (castType.kind()) { case Binding.ARRAY_TYPE : // ( ARRAY ) CLASS if (expressionType.id == T_JavaLangObject) { // potential runtime error - checkUnsafeCast(scope, castType, expressionType, expressionType, true); + if (use15specifics) checkUnsafeCast(scope, castType, expressionType, expressionType, true); tagAsNeedCheckCast(); return true; } @@ -429,21 +441,23 @@ // ( INTERFACE ) CLASS ReferenceBinding refExprType = (ReferenceBinding) expressionType; match = refExprType.findSuperTypeWithSameErasure(castType); - if (refExprType.isFinal()) { - // unless final a subclass may implement the interface ==> no check at compile time - if (match == null) { - return false; - } - return checkUnsafeCast(scope, castType, expressionType, match, false); - } else { - if (match != null) { + if (match != null) { + if (use15specifics) { return checkUnsafeCast(scope, castType, expressionType, match, false); } + return true; + } + // unless final a subclass may implement the interface ==> no check at compile time + if (refExprType.isFinal()) { + return false; } tagAsNeedCheckCast(); match = castType.findSuperTypeWithSameErasure(expressionType); if (match != null) { - return checkUnsafeCast(scope, castType, expressionType, match, true); + if (use15specifics) { + return checkUnsafeCast(scope, castType, expressionType, match, true); + } + return true; } if (use15specifics) { checkUnsafeCast(scope, castType, expressionType, null /*no match*/, true); @@ -457,12 +471,18 @@ match = expressionType.findSuperTypeWithSameErasure(castType); if (match != null) { if (expression != null && castType.id == T_JavaLangString) this.constant = expression.constant; // (String) cst is still a constant - return checkUnsafeCast(scope, castType, expressionType, match, false); + if (use15specifics) { + return checkUnsafeCast(scope, castType, expressionType, match, false); + } + return true; } match = castType.findSuperTypeWithSameErasure(expressionType); if (match != null) { tagAsNeedCheckCast(); - return checkUnsafeCast(scope, castType, expressionType, match, true); + if (use15specifics) { + return checkUnsafeCast(scope, castType, expressionType, match, true); + } + return true; } return false; } Index: compiler/org/eclipse/jdt/internal/compiler/ast/CastExpression.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CastExpression.java,v --- compiler/org/eclipse/jdt/internal/compiler/ast/CastExpression.java 30 Oct 2006 17:27:23 -0000 1.106 +++ compiler/org/eclipse/jdt/internal/compiler/ast/CastExpression.java 22 Nov 2006 14:17:46 -0000 @@ -278,37 +278,62 @@ } return true; } - boolean isCastingToBoundParameterized; - if (match != null && ( - (isCastingToBoundParameterized = castType.isBoundParameterizedType()) - || expressionType.isBoundParameterizedType())) { - - if (match.isProvablyDistinctFrom(isNarrowing ? expressionType : castType, 0)) { - return false; - } - if (isCastingToBoundParameterized - && (isNarrowing ? !expressionType.isEquivalentTo(match) : !match.isEquivalentTo(castType))) { - this.bits |= UnsafeCast; - return true; - } else if ((castType.tagBits & TagBits.HasDirectWildcard) == 0 - && (!match.isParameterizedType() || expressionType.isRawType())) { - this.bits |= UnsafeCast; - return true; - } - } else if (isNarrowing) { - TypeBinding leafType = castType.leafComponentType(); - if (expressionType.id == T_JavaLangObject && castType.isArrayType() && leafType.isBoundParameterizedType()) { - this.bits |= UnsafeCast; - return true; - } - if (match == null && castType.isBoundParameterizedType()) { // cast between unrelated types - this.bits |= UnsafeCast; - return true; - } - if (leafType.isTypeVariable()) { + if (match != null && match.isProvablyDistinctFrom(isNarrowing ? expressionType : castType, 0)) { + return false; + } + switch (castType.kind()) { + case Binding.PARAMETERIZED_TYPE : + if (castType.isBoundParameterizedType()) { + if (match == null) { // unrelated types + this.bits |= UnsafeCast; + return true; + } + switch (match.kind()) { + case Binding.PARAMETERIZED_TYPE : + if (isNarrowing) { + // [JLS 5.5] T <: S + if (expressionType.isRawType() || !expressionType.isEquivalentTo(match)) { + this.bits |= UnsafeCast; + return true; + } + // [JLS 5.5] S has no subtype X != T, such that |X| == |T| + TypeBinding genericCastType = castType.erasure(); // jump to generic type + TypeBinding genericMatch = genericCastType.findSuperTypeWithSameErasure(expressionType); + if (genericMatch == match) { + this.bits |= UnsafeCast; + } + return true; + } else { + // [JLS 5.5] T >: S + if (!match.isEquivalentTo(castType)) { + this.bits |= UnsafeCast; + return true; + } + } + break; + case Binding.RAW_TYPE : + this.bits |= UnsafeCast; // upcast since castType is known to be bound paramType + return true; + default : + if (isNarrowing){ + // match is not parameterized or raw, then any other subtype of match will erase to |T| + this.bits |= UnsafeCast; + return true; + } + break; + } + } + break; + case Binding.ARRAY_TYPE : + TypeBinding leafType = castType.leafComponentType(); + if (isNarrowing && (leafType.isBoundParameterizedType() || leafType.isTypeVariable())) { + this.bits |= UnsafeCast; + return true; + } + break; + case Binding.TYPE_PARAMETER : this.bits |= UnsafeCast; - return true; - } + return true; } if (!isNarrowing && match == this.resolvedType.leafComponentType()) { // do not tag as unnecessary when recursing through upper bounds tagAsUnnecessaryCast(scope, castType);