private final boolean isCoerceableFromParameterizedType(ResolvedType other) { if (!other.isParameterizedType()) return false; ResolvedType myRawType = (ResolvedType) getRawType(); ResolvedType theirRawType = (ResolvedType) other.getRawType(); if (myRawType == theirRawType) { if (getTypeParameters().length == other.getTypeParameters().length) { // there's a chance it can be done ResolvedType[] myTypeParameters = getResolvedTypeParameters(); ResolvedType[] theirTypeParameters = other.getResolvedTypeParameters(); for (int i = 0; i < myTypeParameters.length; i++) { if (myTypeParameters[i] != theirTypeParameters[i]) { // thin ice now... but List<String> may still be coerceable from e.g. List<T> if (myTypeParameters[i].isGenericWildcard()) { BoundedReferenceType wildcard = (BoundedReferenceType) myTypeParameters[i]; if (!wildcard.canBeCoercedTo(theirTypeParameters[i])) return false; } else if (myTypeParameters[i].isTypeVariableReference()) { TypeVariableReferenceType tvrt = (TypeVariableReferenceType) myTypeParameters[i]; TypeVariable tv = tvrt.getTypeVariable(); tv.resolve(world); if (!tv.canBeBoundTo(theirTypeParameters[i])) return false; } else if (theirTypeParameters[i].isTypeVariableReference()) { TypeVariableReferenceType tvrt = (TypeVariableReferenceType) theirTypeParameters[i]; TypeVariable tv = tvrt.getTypeVariable(); tv.resolve(world); if (!tv.canBeBoundTo(myTypeParameters[i])) return false; } else { return false; } } } return true; } } else { // we do this walk for situations like the following: // Base<T>, Sub<S,T> extends Base<S> // is Sub<Y,Z> coerceable from Base<X> ??? for (Iterator i = getDirectSupertypes(); i.hasNext(); ) { ReferenceType parent = (ReferenceType) i.next(); if (parent.isCoerceableFromParameterizedType(other)) return true; } } return false; }
public void testConstructionByNameAndVariable() { TypeVariable tv = new TypeVariable("T", javaLangClass); TypeVariableReferenceType tvrt = new TypeVariableReferenceType(tv, world); assertEquals("T", tvrt.getTypeVariable().getName()); assertEquals(javaLangClass, tvrt.getTypeVariable().getUpperBound()); }
// true iff the statement "this = other" would compile. public boolean isAssignableFrom(ResolvedType other, boolean allowMissing) { if (other.isPrimitiveType()) { if (!world.isInJava5Mode()) return false; if (ResolvedType.validBoxing.contains(this.getSignature() + other.getSignature())) return true; } if (this == other) return true; if (this.getSignature().equals(ResolvedType.OBJECT.getSignature())) return true; if ((this.isRawType() || this.isGenericType()) && other.isParameterizedType()) { if (isAssignableFrom((ResolvedType) other.getRawType())) return true; } if (this.isRawType() && other.isGenericType()) { if (isAssignableFrom((ResolvedType) other.getRawType())) return true; } if (this.isGenericType() && other.isRawType()) { if (isAssignableFrom((ResolvedType) other.getGenericType())) return true; } if (this.isParameterizedType()) { // look at wildcards... if (((ReferenceType) this.getRawType()).isAssignableFrom(other)) { boolean wildcardsAllTheWay = true; ResolvedType[] myParameters = this.getResolvedTypeParameters(); for (int i = 0; i < myParameters.length; i++) { if (!myParameters[i].isGenericWildcard()) { wildcardsAllTheWay = false; } else if (myParameters[i].isExtends() || myParameters[i].isSuper()) { wildcardsAllTheWay = false; } } if (wildcardsAllTheWay && !other.isParameterizedType()) return true; // we have to match by parameters one at a time ResolvedType[] theirParameters = other.getResolvedTypeParameters(); boolean parametersAssignable = true; if (myParameters.length == theirParameters.length) { for (int i = 0; i < myParameters.length; i++) { if (myParameters[i] == theirParameters[i]) continue; if (myParameters[i].isAssignableFrom(theirParameters[i], allowMissing)) { continue; } if (!myParameters[i].isGenericWildcard()) { parametersAssignable = false; break; } else { BoundedReferenceType wildcardType = (BoundedReferenceType) myParameters[i]; if (!wildcardType.alwaysMatches(theirParameters[i])) { parametersAssignable = false; break; } } } } else { parametersAssignable = false; } if (parametersAssignable) return true; } } if (isTypeVariableReference() && !other.isTypeVariableReference()) { // eg. this=T other=Ljava/lang/Object; TypeVariable aVar = ((TypeVariableReference) this).getTypeVariable(); return aVar.resolve(world).canBeBoundTo(other); } if (other.isTypeVariableReference()) { TypeVariableReferenceType otherType = (TypeVariableReferenceType) other; if (this instanceof TypeVariableReference) { return ((TypeVariableReference) this) .getTypeVariable() .canBeBoundTo(otherType.getTypeVariable().getFirstBound().resolve(world)); // pr171952 // return // ((TypeVariableReference)this).getTypeVariable()==otherType.getTypeVariable(); } else { // FIXME asc should this say canBeBoundTo?? return this.isAssignableFrom(otherType.getTypeVariable().getFirstBound().resolve(world)); } } if (allowMissing && other.isMissing()) return false; for (Iterator i = other.getDirectSupertypes(); i.hasNext(); ) { if (this.isAssignableFrom((ResolvedType) i.next(), allowMissing)) return true; } return false; }