/* Answer true if the receiver type can be assigned to the argument type (right) */ public boolean isCompatibleWith(TypeBinding otherType) { if (this == otherType) return true; switch (otherType.kind()) { case Binding.ARRAY_TYPE: ArrayBinding otherArray = (ArrayBinding) otherType; if (otherArray.leafComponentType.isBaseType()) return false; // relying on the fact that all equal arrays are identical if (dimensions == otherArray.dimensions) return leafComponentType.isCompatibleWith(otherArray.leafComponentType); if (dimensions < otherArray.dimensions) return false; // cannot assign 'String[]' into 'Object[][]' but can assign 'byte[][]' into // 'Object[]' break; case Binding.BASE_TYPE: return false; case Binding.WILDCARD_TYPE: case Binding.INTERSECTION_TYPE: return ((WildcardBinding) otherType).boundCheck(this); case Binding.TYPE_PARAMETER: // check compatibility with capture of ? super X if (otherType.isCapture()) { CaptureBinding otherCapture = (CaptureBinding) otherType; TypeBinding otherLowerBound; if ((otherLowerBound = otherCapture.lowerBound) != null) { if (!otherLowerBound.isArrayType()) return false; return this.isCompatibleWith(otherLowerBound); } } return false; } // Check dimensions - Java does not support explicitly sized dimensions for types. // However, if it did, the type checking support would go here. switch (otherType.leafComponentType().id) { case TypeIds.T_JavaLangObject: case TypeIds.T_JavaLangCloneable: case TypeIds.T_JavaIoSerializable: return true; } return false; }
/** * Collect the substitutes into a map for certain type variables inside the receiver type e.g. * Collection<T>.collectSubstitutes(Collection<List<X>>, Map), will populate Map with: T --> * List<X> Constraints: A << F corresponds to: F.collectSubstitutes(..., A, ..., * CONSTRAINT_EXTENDS (1)) A = F corresponds to: F.collectSubstitutes(..., A, ..., * CONSTRAINT_EQUAL (0)) A >> F corresponds to: F.collectSubstitutes(..., A, ..., CONSTRAINT_SUPER * (2)) */ public void collectSubstitutes( Scope scope, TypeBinding actualType, InferenceContext inferenceContext, int constraint) { if ((this.tagBits & TagBits.HasTypeVariable) == 0) return; if (actualType == TypeBinding.NULL) return; if (actualType.isCapture()) { CaptureBinding capture = (CaptureBinding) actualType; actualType = capture.wildcard; } switch (constraint) { case TypeConstants.CONSTRAINT_EXTENDS: // A << F switch (this.boundKind) { case Wildcard.UNBOUND: // F={?} // switch (actualType.kind()) { // case Binding.WILDCARD_TYPE : // WildcardBinding actualWildcard = (WildcardBinding) actualType; // switch(actualWildcard.kind) { // case Wildcard.UNBOUND: // A={?} << F={?} --> 0 // break; // case Wildcard.EXTENDS: // A={? extends V} << F={?} ---> 0 // break; // case Wildcard.SUPER: // A={? super V} << F={?} ---> 0 // break; // } // break; // case Binding.INTERSECTION_TYPE :// A={? extends V1&...&Vn} << F={?} ---> 0 // break; // default :// A=V << F={?} ---> 0 // break; // } break; case Wildcard.EXTENDS: // F={? extends U} switch (actualType.kind()) { case Binding.WILDCARD_TYPE: WildcardBinding actualWildcard = (WildcardBinding) actualType; switch (actualWildcard.boundKind) { case Wildcard.UNBOUND: // A={?} << F={? extends U} --> 0 break; case Wildcard.EXTENDS: // A={? extends V} << F={? extends U} ---> V << U this.bound.collectSubstitutes( scope, actualWildcard.bound, inferenceContext, TypeConstants.CONSTRAINT_EXTENDS); break; case Wildcard.SUPER: // A={? super V} << F={? extends U} ---> 0 break; } break; case Binding .INTERSECTION_TYPE: // A={? extends V1&...&Vn} << F={? extends U} ---> V1 << U, // ..., Vn << U WildcardBinding actualIntersection = (WildcardBinding) actualType; this.bound.collectSubstitutes( scope, actualIntersection.bound, inferenceContext, TypeConstants.CONSTRAINT_EXTENDS); for (int i = 0, length = actualIntersection.otherBounds.length; i < length; i++) { this.bound.collectSubstitutes( scope, actualIntersection.otherBounds[i], inferenceContext, TypeConstants.CONSTRAINT_EXTENDS); } break; default: // A=V << F={? extends U} ---> V << U this.bound.collectSubstitutes( scope, actualType, inferenceContext, TypeConstants.CONSTRAINT_EXTENDS); break; } break; case Wildcard.SUPER: // F={? super U} switch (actualType.kind()) { case Binding.WILDCARD_TYPE: WildcardBinding actualWildcard = (WildcardBinding) actualType; switch (actualWildcard.boundKind) { case Wildcard.UNBOUND: // A={?} << F={? super U} --> 0 break; case Wildcard.EXTENDS: // A={? extends V} << F={? super U} ---> 0 break; case Wildcard.SUPER: // A={? super V} << F={? super U} ---> 0 this.bound.collectSubstitutes( scope, actualWildcard.bound, inferenceContext, TypeConstants.CONSTRAINT_SUPER); for (int i = 0, length = actualWildcard.otherBounds == null ? 0 : actualWildcard.otherBounds.length; i < length; i++) { this.bound.collectSubstitutes( scope, actualWildcard.otherBounds[i], inferenceContext, TypeConstants.CONSTRAINT_SUPER); } break; } break; case Binding.INTERSECTION_TYPE: // A={? extends V1&...&Vn} << F={? super U} ---> 0 break; default: // A=V << F={? super U} ---> V >> U this.bound.collectSubstitutes( scope, actualType, inferenceContext, TypeConstants.CONSTRAINT_SUPER); break; } break; } break; case TypeConstants.CONSTRAINT_EQUAL: // A == F switch (this.boundKind) { case Wildcard.UNBOUND: // F={?} // switch (actualType.kind()) { // case Binding.WILDCARD_TYPE : // WildcardBinding actualWildcard = (WildcardBinding) actualType; // switch(actualWildcard.kind) { // case Wildcard.UNBOUND: // A={?} == F={?} --> 0 // break; // case Wildcard.EXTENDS: // A={? extends V} == F={?} ---> 0 // break; // case Wildcard.SUPER: // A={? super V} == F={?} ---> 0 // break; // } // break; // case Binding.INTERSECTION_TYPE :// A={? extends V1&...&Vn} == F={?} ---> 0 // break; // default :// A=V == F={?} ---> 0 // break; // } break; case Wildcard.EXTENDS: // F={? extends U} switch (actualType.kind()) { case Binding.WILDCARD_TYPE: WildcardBinding actualWildcard = (WildcardBinding) actualType; switch (actualWildcard.boundKind) { case Wildcard.UNBOUND: // A={?} == F={? extends U} --> 0 break; case Wildcard.EXTENDS: // A={? extends V} == F={? extends U} ---> V == U this.bound.collectSubstitutes( scope, actualWildcard.bound, inferenceContext, TypeConstants.CONSTRAINT_EQUAL); for (int i = 0, length = actualWildcard.otherBounds == null ? 0 : actualWildcard.otherBounds.length; i < length; i++) { this.bound.collectSubstitutes( scope, actualWildcard.otherBounds[i], inferenceContext, TypeConstants.CONSTRAINT_EQUAL); } break; case Wildcard.SUPER: // A={? super V} == F={? extends U} ---> 0 break; } break; case Binding .INTERSECTION_TYPE: // A={? extends V1&...&Vn} == F={? extends U} ---> V1 == U, // ..., Vn == U WildcardBinding actuaIntersection = (WildcardBinding) actualType; this.bound.collectSubstitutes( scope, actuaIntersection.bound, inferenceContext, TypeConstants.CONSTRAINT_EQUAL); for (int i = 0, length = actuaIntersection.otherBounds == null ? 0 : actuaIntersection.otherBounds.length; i < length; i++) { this.bound.collectSubstitutes( scope, actuaIntersection.otherBounds[i], inferenceContext, TypeConstants.CONSTRAINT_EQUAL); } break; default: // A=V == F={? extends U} ---> 0 break; } break; case Wildcard.SUPER: // F={? super U} switch (actualType.kind()) { case Binding.WILDCARD_TYPE: WildcardBinding actualWildcard = (WildcardBinding) actualType; switch (actualWildcard.boundKind) { case Wildcard.UNBOUND: // A={?} == F={? super U} --> 0 break; case Wildcard.EXTENDS: // A={? extends V} == F={? super U} ---> 0 break; case Wildcard.SUPER: // A={? super V} == F={? super U} ---> 0 this.bound.collectSubstitutes( scope, actualWildcard.bound, inferenceContext, TypeConstants.CONSTRAINT_EQUAL); for (int i = 0, length = actualWildcard.otherBounds == null ? 0 : actualWildcard.otherBounds.length; i < length; i++) { this.bound.collectSubstitutes( scope, actualWildcard.otherBounds[i], inferenceContext, TypeConstants.CONSTRAINT_EQUAL); } break; } break; case Binding.INTERSECTION_TYPE: // A={? extends V1&...&Vn} == F={? super U} ---> 0 break; default: // A=V == F={? super U} ---> 0 break; } break; } break; case TypeConstants.CONSTRAINT_SUPER: // A >> F switch (this.boundKind) { case Wildcard.UNBOUND: // F={?} // switch (actualType.kind()) { // case Binding.WILDCARD_TYPE : // WildcardBinding actualWildcard = (WildcardBinding) actualType; // switch(actualWildcard.kind) { // case Wildcard.UNBOUND: // A={?} >> F={?} --> 0 // break; // case Wildcard.EXTENDS: // A={? extends V} >> F={?} ---> 0 // break; // case Wildcard.SUPER: // A={? super V} >> F={?} ---> 0 // break; // } // break; // case Binding.INTERSECTION_TYPE :// A={? extends V1&...&Vn} >> F={?} ---> 0 // break; // default :// A=V >> F={?} ---> 0 // break; // } break; case Wildcard.EXTENDS: // F={? extends U} switch (actualType.kind()) { case Binding.WILDCARD_TYPE: WildcardBinding actualWildcard = (WildcardBinding) actualType; switch (actualWildcard.boundKind) { case Wildcard.UNBOUND: // A={?} >> F={? extends U} --> 0 break; case Wildcard.EXTENDS: // A={? extends V} >> F={? extends U} ---> V >> U this.bound.collectSubstitutes( scope, actualWildcard.bound, inferenceContext, TypeConstants.CONSTRAINT_SUPER); for (int i = 0, length = actualWildcard.otherBounds == null ? 0 : actualWildcard.otherBounds.length; i < length; i++) { this.bound.collectSubstitutes( scope, actualWildcard.otherBounds[i], inferenceContext, TypeConstants.CONSTRAINT_SUPER); } break; case Wildcard.SUPER: // A={? super V} >> F={? extends U} ---> 0 break; } break; case Binding .INTERSECTION_TYPE: // A={? extends V1&...&Vn} >> F={? extends U} ---> V1 >> U, // ..., Vn >> U WildcardBinding actualIntersection = (WildcardBinding) actualType; this.bound.collectSubstitutes( scope, actualIntersection.bound, inferenceContext, TypeConstants.CONSTRAINT_SUPER); for (int i = 0, length = actualIntersection.otherBounds == null ? 0 : actualIntersection.otherBounds.length; i < length; i++) { this.bound.collectSubstitutes( scope, actualIntersection.otherBounds[i], inferenceContext, TypeConstants.CONSTRAINT_SUPER); } break; default: // A=V == F={? extends U} ---> 0 break; } break; case Wildcard.SUPER: // F={? super U} switch (actualType.kind()) { case Binding.WILDCARD_TYPE: WildcardBinding actualWildcard = (WildcardBinding) actualType; switch (actualWildcard.boundKind) { case Wildcard.UNBOUND: // A={?} >> F={? super U} --> 0 break; case Wildcard.EXTENDS: // A={? extends V} >> F={? super U} ---> 0 break; case Wildcard.SUPER: // A={? super V} >> F={? super U} ---> V >> U this.bound.collectSubstitutes( scope, actualWildcard.bound, inferenceContext, TypeConstants.CONSTRAINT_SUPER); for (int i = 0, length = actualWildcard.otherBounds == null ? 0 : actualWildcard.otherBounds.length; i < length; i++) { this.bound.collectSubstitutes( scope, actualWildcard.otherBounds[i], inferenceContext, TypeConstants.CONSTRAINT_SUPER); } break; } break; case Binding.INTERSECTION_TYPE: // A={? extends V1&...&Vn} >> F={? super U} ---> 0 break; default: // A=V >> F={? super U} ---> 0 break; } break; } break; } }