/** * A restricted version of areClassTypesAssignable that is used for comparing the type arguments * of parameterized types, where the lhsTypeArg is the container. */ private static boolean doesTypeArgumentContain(JClassType lhsTypeArg, JClassType rhsTypeArg) { if (lhsTypeArg == rhsTypeArg) { return true; } // Check for wildcard types JWildcardType lhsWildcard = lhsTypeArg.isWildcard(); JWildcardType rhsWildcard = rhsTypeArg.isWildcard(); if (lhsWildcard != null) { if (rhsWildcard != null) { return areWildcardsAssignable(lhsWildcard, rhsWildcard); } else { // LHS is a wildcard but the RHS is not. if (lhsWildcard.getLowerBounds().length > 0) { return areClassTypesAssignable(rhsTypeArg, lhsWildcard.getFirstBound()); } else { return areClassTypesAssignable(lhsWildcard.getFirstBound(), rhsTypeArg); } } } /* * At this point the arguments are not the same and they are not wildcards * so, they cannot be assignable, Eh. */ return false; }
/** * Returns <code>true</code> if the rhsWildcard can be assigned to the lhsWildcard. This method * does not consider supertypes of either lhs or rhs. */ private static boolean areWildcardsAssignable( JWildcardType lhsWildcard, JWildcardType rhsWildcard) { // areClassTypesAssignable should prevent us from getting here if the types // are referentially equal. assert (lhsWildcard != rhsWildcard); assert (lhsWildcard != null && rhsWildcard != null); if (lhsWildcard.getLowerBounds().length > 0 && rhsWildcard.getLowerBounds().length > 0) { // lhsType: ? super T, rhsType ? super U return areClassTypesAssignable(rhsWildcard.getFirstBound(), lhsWildcard.getFirstBound()); } else if (lhsWildcard.getUpperBounds().length > 0 && lhsWildcard.getLowerBounds().length == 0 && rhsWildcard.getUpperBounds().length > 0 && rhsWildcard.getLowerBounds().length == 0) { // lhsType: ? extends T, rhsType: ? extends U return areClassTypesAssignable(lhsWildcard.getFirstBound(), rhsWildcard.getFirstBound()); } return false; }
/** * Returns <code>true</code> if the lhs and rhs are assignable without consideration of the * supertypes of the rhs. * * @param lhsType * @param rhsType * @return true if rhsType can be assigned to lhsType */ private static boolean areClassTypesAssignableNoSupers(JClassType lhsType, JClassType rhsType) { if (lhsType == rhsType) { // Done, these are the same types. return true; } if (lhsType == lhsType.getOracle().getJavaLangObject()) { // Done, any type can be assigned to object. return true; } /* * Get the generic base type, if there is one, for the lhs type and convert * it to a raw type if it is generic. */ if (lhsType.isGenericType() != null) { lhsType = lhsType.isGenericType().getRawType(); } if (rhsType.isGenericType() != null) { // Treat the generic rhs type as a raw type. rhsType = rhsType.isGenericType().getRawType(); } // Check for JTypeParameters. JTypeParameter lhsTypeParam = lhsType.isTypeParameter(); JTypeParameter rhsTypeParam = rhsType.isTypeParameter(); if (lhsTypeParam != null) { JClassType[] lhsTypeBounds = lhsTypeParam.getBounds(); for (JClassType lhsTypeBound : lhsTypeBounds) { if (!areClassTypesAssignable(lhsTypeBound, rhsType)) { // Done, the rhsType was not assignable to one of the bounds. return false; } } // Done, the rhsType was assignable to all of the bounds. return true; } else if (rhsTypeParam != null) { JClassType[] possibleSubtypeBounds = rhsTypeParam.getBounds(); for (JClassType possibleSubtypeBound : possibleSubtypeBounds) { if (areClassTypesAssignable(lhsType, possibleSubtypeBound)) { // Done, at least one bound is assignable to this type. return true; } } return false; } /* * Check for JWildcards. We have not examined this part in great detail * since there should not be top level wildcard types. */ JWildcardType lhsWildcard = lhsType.isWildcard(); JWildcardType rhsWildcard = rhsType.isWildcard(); if (lhsWildcard != null && rhsWildcard != null) { // Both types are wildcards. return areWildcardsAssignable(lhsWildcard, rhsWildcard); } else if (lhsWildcard != null) { // The lhs type is a wildcard but the rhs is not. // ? extends T, U OR ? super T, U JClassType[] lowerBounds = lhsWildcard.getLowerBounds(); if (lowerBounds.length > 0) { // ? super T will reach object no matter what the rhs type is return true; } else { return areClassTypesAssignable(lhsWildcard.getFirstBound(), rhsType); } } // Check for JArrayTypes. JArrayType lhsArray = lhsType.isArray(); JArrayType rhsArray = rhsType.isArray(); if (lhsArray != null) { if (rhsArray == null) { return false; } else { return areArraysAssignable(lhsArray, rhsArray); } } else if (rhsArray != null) { // Safe although perhaps not necessary return false; } // Check for JParameterizedTypes and JRawTypes. JMaybeParameterizedType lhsMaybeParameterized = lhsType.isMaybeParameterizedType(); JMaybeParameterizedType rhsMaybeParameterized = rhsType.isMaybeParameterizedType(); if (lhsMaybeParameterized != null && rhsMaybeParameterized != null) { if (lhsMaybeParameterized.getBaseType() == rhsMaybeParameterized.getBaseType()) { if (lhsMaybeParameterized.isRawType() != null || rhsMaybeParameterized.isRawType() != null) { /* * Any raw type can be assigned to or from any parameterization of its * generic type. */ return true; } assert (lhsMaybeParameterized.isRawType() == null && rhsMaybeParameterized.isRawType() == null); JParameterizedType lhsParameterized = lhsMaybeParameterized.isParameterized(); JParameterizedType rhsParameterized = rhsMaybeParameterized.isParameterized(); assert (lhsParameterized != null && rhsParameterized != null); return areTypeArgumentsAssignable(lhsParameterized, rhsParameterized); } } // Default to not being assignable. return false; }