blob: a3aba199c014566f387ff449f5b7e1c9bc879fd2 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2013 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* This is an implementation of an early-draft specification developed under the Java
* Community Process (JCP) and is made available for testing and evaluation purposes
* only. The code is not compatible with any specification of the JCP.
*
* Contributors:
* IBM Corporation - initial API and implementation
* Fraunhofer FIRST - extended API and implementation
* Technical University Berlin - extended API and implementation
* Stephen Herrmann <stephan@cs.tu-berlin.de> - Contributions for
* bug 317046 - Exception during debugging when hover mouse over a field
* bug 395002 - Self bound generic class doesn't resolve bounds properly for wildcards for certain parametrisation.
* bug 392862 - [1.8][compiler][null] Evaluate null annotations on array types
* Jesper S Moller <jesper@selskabet.org> - Contributions for
* bug 382701 - [1.8][compiler] Implement semantic analysis of Lambda expressions & Reference expression
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.lookup;
import java.util.List;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.internal.compiler.ast.Wildcard;
import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.DependentTypeBinding;
import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.RoleTypeBinding;
/**
* OTDT changes:
* What: beautify signature for completion
*
* What: introduce new queries isRole() isTeam() valueParamSynthArgs()
*
*
*
* Not all fields defined by this type (& its subclasses) are initialized when it is created.
* Some are initialized only when needed.
*
* Accessors have been provided for some public fields so all TypeBindings have the same API...
* but access public fields directly whenever possible.
* Non-public fields have accessors which should be used everywhere you expect the field to be initialized.
*
* null is NOT a valid value for a non-public field... it just means the field is not initialized.
*/
abstract public class TypeBinding extends Binding {
public int id = TypeIds.NoId;
public long tagBits = 0; // See values in the interface TagBits below
/** Base type definitions */
public final static BaseTypeBinding INT = new BaseTypeBinding(
TypeIds.T_int, TypeConstants.INT, new char[] { 'I' });
public final static BaseTypeBinding BYTE = new BaseTypeBinding(
TypeIds.T_byte, TypeConstants.BYTE, new char[] { 'B' });
public final static BaseTypeBinding SHORT = new BaseTypeBinding(
TypeIds.T_short, TypeConstants.SHORT, new char[] { 'S' });
public final static BaseTypeBinding CHAR = new BaseTypeBinding(
TypeIds.T_char, TypeConstants.CHAR, new char[] { 'C' });
public final static BaseTypeBinding LONG = new BaseTypeBinding(
TypeIds.T_long, TypeConstants.LONG, new char[] { 'J' });
public final static BaseTypeBinding FLOAT = new BaseTypeBinding(
TypeIds.T_float, TypeConstants.FLOAT, new char[] { 'F' });
public final static BaseTypeBinding DOUBLE = new BaseTypeBinding(
TypeIds.T_double, TypeConstants.DOUBLE, new char[] { 'D' });
public final static BaseTypeBinding BOOLEAN = new BaseTypeBinding(
TypeIds.T_boolean, TypeConstants.BOOLEAN, new char[] { 'Z' });
public final static BaseTypeBinding NULL = new BaseTypeBinding(
TypeIds.T_null, TypeConstants.NULL, new char[] { 'N' }); //N stands for null even if it is never internally used
public final static BaseTypeBinding VOID = new BaseTypeBinding(
TypeIds.T_void, TypeConstants.VOID, new char[] { 'V' });
/**
* Match a well-known type id to its binding
*/
public static final TypeBinding wellKnownType(Scope scope, int id) {
switch (id) {
case TypeIds.T_boolean:
return TypeBinding.BOOLEAN;
case TypeIds.T_byte:
return TypeBinding.BYTE;
case TypeIds.T_char:
return TypeBinding.CHAR;
case TypeIds.T_short:
return TypeBinding.SHORT;
case TypeIds.T_double:
return TypeBinding.DOUBLE;
case TypeIds.T_float:
return TypeBinding.FLOAT;
case TypeIds.T_int:
return TypeBinding.INT;
case TypeIds.T_long:
return TypeBinding.LONG;
case TypeIds.T_JavaLangObject:
return scope.getJavaLangObject();
case TypeIds.T_JavaLangString:
return scope.getJavaLangString();
default:
return null;
}
}
/* Answer true if the receiver can be instantiated
*/
public boolean canBeInstantiated() {
return !isBaseType();
}
/**
* Perform capture conversion on a given type (only effective on parameterized type with wildcards)
*/
public TypeBinding capture(Scope scope, int position) {
return this;
}
/**
* In case of problems, returns the closest match found. It may not be perfect match, but the
* result of a best effort to improve fault-tolerance.
*/
public TypeBinding closestMatch() {
return this; // by default no better type
}
/**
* Iterate through the type components to collect instances of leaf missing types
* @param missingTypes
* @return missing types
*/
public List collectMissingTypes(List missingTypes) {
return missingTypes;
}
/**
* Collect the substitutes into a map for certain type variables inside the receiver type
* e.g. Collection<T>.findSubstitute(T, Collection<List<X>>): 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) {
// no substitute by default
}
/**
* Answer the receiver's constant pool name.
* NOTE: This method should only be used during/after code gen.
* e.g. 'java/lang/Object'
*/
public abstract char[] constantPoolName();
public String debugName() {
return new String(readableName());
}
/*
* Answer the receiver's dimensions - 0 for non-array types
*/
public int dimensions() {
return 0;
}
/* Answer the receiver's enclosing type... null if the receiver is a top level type.
*/
public ReferenceBinding enclosingType() {
return null;
}
public TypeBinding erasure() {
return this;
}
/**
* Find supertype which originates from a given well-known type, or null if not found
* (using id avoids triggering the load of well-known type: 73740)
* NOTE: only works for erasures of well-known types, as random other types may share
* same id though being distincts.
* @see TypeIds
*/
public ReferenceBinding findSuperTypeOriginatingFrom(int wellKnownOriginalID, boolean originalIsClass) {
if (!(this instanceof ReferenceBinding)) return null;
ReferenceBinding reference = (ReferenceBinding) this;
// do not allow type variables to match with erasures for free
if (reference.id == wellKnownOriginalID || (original().id == wellKnownOriginalID)) return reference;
ReferenceBinding currentType = reference;
// iterate superclass to avoid recording interfaces if searched supertype is class
if (originalIsClass) {
while ((currentType = currentType.superclass()) != null) {
if (currentType.id == wellKnownOriginalID)
return currentType;
if (currentType.original().id == wellKnownOriginalID)
return currentType;
}
return null;
}
ReferenceBinding[] interfacesToVisit = null;
int nextPosition = 0;
do {
ReferenceBinding[] itsInterfaces = currentType.superInterfaces();
if (itsInterfaces != null && itsInterfaces != Binding.NO_SUPERINTERFACES) {
if (interfacesToVisit == null) {
interfacesToVisit = itsInterfaces;
nextPosition = interfacesToVisit.length;
} else {
int itsLength = itsInterfaces.length;
if (nextPosition + itsLength >= interfacesToVisit.length)
System.arraycopy(interfacesToVisit, 0, interfacesToVisit = new ReferenceBinding[nextPosition + itsLength + 5], 0, nextPosition);
nextInterface : for (int a = 0; a < itsLength; a++) {
ReferenceBinding next = itsInterfaces[a];
for (int b = 0; b < nextPosition; b++)
if (next == interfacesToVisit[b]) continue nextInterface;
interfacesToVisit[nextPosition++] = next;
}
}
}
} while ((currentType = currentType.superclass()) != null);
for (int i = 0; i < nextPosition; i++) {
currentType = interfacesToVisit[i];
if (currentType.id == wellKnownOriginalID)
return currentType;
if (currentType.original().id == wellKnownOriginalID)
return currentType;
ReferenceBinding[] itsInterfaces = currentType.superInterfaces();
if (itsInterfaces != null && itsInterfaces != Binding.NO_SUPERINTERFACES) {
int itsLength = itsInterfaces.length;
if (nextPosition + itsLength >= interfacesToVisit.length)
System.arraycopy(interfacesToVisit, 0, interfacesToVisit = new ReferenceBinding[nextPosition + itsLength + 5], 0, nextPosition);
nextInterface : for (int a = 0; a < itsLength; a++) {
ReferenceBinding next = itsInterfaces[a];
for (int b = 0; b < nextPosition; b++)
if (next == interfacesToVisit[b]) continue nextInterface;
interfacesToVisit[nextPosition++] = next;
}
}
}
return null;
}
/**
* Find supertype which originates from a given type, or null if not found
*/
public TypeBinding findSuperTypeOriginatingFrom(TypeBinding otherType) {
if (this == otherType) return this;
if (otherType == null) return null;
switch(kind()) {
case Binding.ARRAY_TYPE :
ArrayBinding arrayType = (ArrayBinding) this;
int otherDim = otherType.dimensions();
if (arrayType.dimensions != otherDim) {
switch(otherType.id) {
case TypeIds.T_JavaLangObject :
case TypeIds.T_JavaIoSerializable :
case TypeIds.T_JavaLangCloneable :
return otherType;
}
if (otherDim < arrayType.dimensions && otherType.leafComponentType().id == TypeIds.T_JavaLangObject) {
return otherType; // X[][] has Object[] as an implicit supertype
}
return null;
}
if (!(arrayType.leafComponentType instanceof ReferenceBinding)) return null;
TypeBinding leafSuperType = arrayType.leafComponentType.findSuperTypeOriginatingFrom(otherType.leafComponentType());
if (leafSuperType == null) return null;
return arrayType.environment().createArrayType(leafSuperType, arrayType.dimensions);
case Binding.TYPE_PARAMETER :
if (isCapture()) {
CaptureBinding capture = (CaptureBinding) this;
TypeBinding captureBound = capture.firstBound;
if (captureBound instanceof ArrayBinding) {
TypeBinding match = captureBound.findSuperTypeOriginatingFrom(otherType);
if (match != null) return match;
}
}
//$FALL-THROUGH$
case Binding.TYPE :
case Binding.PARAMETERIZED_TYPE :
case Binding.GENERIC_TYPE :
case Binding.RAW_TYPE :
case Binding.WILDCARD_TYPE :
case Binding.INTERSECTION_TYPE:
// do not allow type variables/intersection types to match with erasures for free
otherType = otherType.original();
if (this == otherType)
return this;
if (original() == otherType)
return this;
ReferenceBinding currentType = (ReferenceBinding)this;
if (!otherType.isInterface()) {
while ((currentType = currentType.superclass()) != null) {
if (currentType == otherType)
return currentType;
if (currentType.original() == otherType)
return currentType;
}
return null;
}
ReferenceBinding[] interfacesToVisit = null;
int nextPosition = 0;
do {
ReferenceBinding[] itsInterfaces = currentType.superInterfaces();
if (itsInterfaces != null && itsInterfaces != Binding.NO_SUPERINTERFACES) {
if (interfacesToVisit == null) {
interfacesToVisit = itsInterfaces;
nextPosition = interfacesToVisit.length;
} else {
int itsLength = itsInterfaces.length;
if (nextPosition + itsLength >= interfacesToVisit.length)
System.arraycopy(interfacesToVisit, 0, interfacesToVisit = new ReferenceBinding[nextPosition + itsLength + 5], 0, nextPosition);
nextInterface : for (int a = 0; a < itsLength; a++) {
ReferenceBinding next = itsInterfaces[a];
for (int b = 0; b < nextPosition; b++)
if (next == interfacesToVisit[b]) continue nextInterface;
interfacesToVisit[nextPosition++] = next;
}
}
}
} while ((currentType = currentType.superclass()) != null);
for (int i = 0; i < nextPosition; i++) {
currentType = interfacesToVisit[i];
if (currentType == otherType)
return currentType;
if (currentType.original() == otherType)
return currentType;
ReferenceBinding[] itsInterfaces = currentType.superInterfaces();
if (itsInterfaces != null && itsInterfaces != Binding.NO_SUPERINTERFACES) {
int itsLength = itsInterfaces.length;
if (nextPosition + itsLength >= interfacesToVisit.length)
System.arraycopy(interfacesToVisit, 0, interfacesToVisit = new ReferenceBinding[nextPosition + itsLength + 5], 0, nextPosition);
nextInterface : for (int a = 0; a < itsLength; a++) {
ReferenceBinding next = itsInterfaces[a];
for (int b = 0; b < nextPosition; b++)
if (next == interfacesToVisit[b]) continue nextInterface;
interfacesToVisit[nextPosition++] = next;
}
}
}
}
return null;
}
/**
* Returns the type to use for generic cast, or null if none required
*/
public TypeBinding genericCast(TypeBinding targetType) {
if (this == targetType)
return null;
TypeBinding targetErasure = targetType.erasure();
// type var get replaced by upper bound
if (erasure().findSuperTypeOriginatingFrom(targetErasure) != null)
return null;
//{ObjectTeams: don't cast if lowering is needed instead:
TypeBinding erasure= erasure();
if ( erasure.isRole()
&& targetErasure == ((ReferenceBinding)erasure).baseclass())
return null;
// SH}
return targetErasure;
}
//{ObjectTeams: beautify for completion:
public char[] genericTypeSignature(boolean retrenchCallin) {
return genericTypeSignature(); // no difference here.
}
// SH}
/**
* Answer the receiver classfile signature.
* Arrays & base types do not distinguish between signature() & constantPoolName().
* NOTE: This method should only be used during/after code gen.
*/
public char[] genericTypeSignature() {
return signature();
}
/**
* Return the supertype which would erase as a subtype of a given declaring class.
* If the receiver is already erasure compatible, then it will returned. If not, then will return the alternate lowest
* upper bound compatible with declaring class.
* NOTE: the declaringClass is already know to be compatible with the receiver
* @param declaringClass to look for
* @return the lowest erasure compatible type (considering alternate bounds)
*/
public TypeBinding getErasureCompatibleType(TypeBinding declaringClass) {
switch(kind()) {
case Binding.TYPE_PARAMETER :
TypeVariableBinding variable = (TypeVariableBinding) this;
if (variable.erasure().findSuperTypeOriginatingFrom(declaringClass) != null) {
return this; // no need for alternate receiver type
}
if (variable.superclass != null && variable.superclass.findSuperTypeOriginatingFrom(declaringClass) != null) {
return variable.superclass.getErasureCompatibleType(declaringClass);
}
for (int i = 0, otherLength = variable.superInterfaces.length; i < otherLength; i++) {
ReferenceBinding superInterface = variable.superInterfaces[i];
if (superInterface.findSuperTypeOriginatingFrom(declaringClass) != null) {
return superInterface.getErasureCompatibleType(declaringClass);
}
}
return this; // only occur if passed null declaringClass for arraylength
case Binding.INTERSECTION_TYPE :
WildcardBinding intersection = (WildcardBinding) this;
if (intersection.erasure().findSuperTypeOriginatingFrom(declaringClass) != null) {
return this; // no need for alternate receiver type
}
if (intersection.superclass != null && intersection.superclass.findSuperTypeOriginatingFrom(declaringClass) != null) {
return intersection.superclass.getErasureCompatibleType(declaringClass);
}
for (int i = 0, otherLength = intersection.superInterfaces.length; i < otherLength; i++) {
ReferenceBinding superInterface = intersection.superInterfaces[i];
if (superInterface.findSuperTypeOriginatingFrom(declaringClass) != null) {
return superInterface.getErasureCompatibleType(declaringClass);
}
}
return this; // only occur if passed null declaringClass for arraylength
default :
return this;
}
}
public abstract PackageBinding getPackage();
//{ObjectTeams: accessible across AbstractOTReferenceBinding (sitting in a different package):
protected
// SH}
void initializeForStaticImports() {
// only applicable to source types
}
public boolean isAnnotationType() {
return false;
}
public final boolean isAnonymousType() {
return (this.tagBits & TagBits.IsAnonymousType) != 0;
}
/* Answer true if the receiver is an array
*/
public final boolean isArrayType() {
return (this.tagBits & TagBits.IsArrayType) != 0;
}
/* Answer true if the receiver is a base type
*/
public final boolean isBaseType() {
return (this.tagBits & TagBits.IsBaseType) != 0;
}
/* Answer true if the receiver is a primitive type or a boxed primitive type
*/
public final boolean isPrimitiveOrBoxedPrimitiveType() {
if ((this.tagBits & TagBits.IsBaseType) != 0)
return true;
switch (this.id) {
case TypeIds.T_JavaLangBoolean :
case TypeIds.T_JavaLangByte :
case TypeIds.T_JavaLangCharacter :
case TypeIds.T_JavaLangShort :
case TypeIds.T_JavaLangDouble :
case TypeIds.T_JavaLangFloat :
case TypeIds.T_JavaLangInteger :
case TypeIds.T_JavaLangLong :
return true;
default:
return false;
}
}
/**
* Returns true if parameterized type AND not of the form List<?>
*/
public boolean isBoundParameterizedType() {
return (this.tagBits & TagBits.IsBoundParameterizedType) != 0;
}
/**
* Returns true if the type is the capture of some wildcard
*/
public boolean isCapture() {
return false;
}
public boolean isClass() {
return false;
}
/* Answer true if the receiver type can be assigned to the argument type (right)
*/
public boolean isCompatibleWith(TypeBinding right) {
return isCompatibleWith(right, null); // delegate from the old signature to the new implementation:
}
// version that allows to capture a type bound using 'scope':
public abstract boolean isCompatibleWith(TypeBinding right, /*@Nullable*/ Scope scope);
public boolean isEnum() {
return false;
}
/**
* Returns true if a type is identical to another one,
* or for generic types, true if compared to its raw type.
*/
public boolean isEquivalentTo(TypeBinding otherType) {
if (this == otherType)
return true;
if (otherType == null)
return false;
switch (otherType.kind()) {
case Binding.WILDCARD_TYPE :
case Binding.INTERSECTION_TYPE :
return ((WildcardBinding) otherType).boundCheck(this);
}
return false;
}
public boolean isGenericType() {
return false;
}
/* Answer true if the receiver's hierarchy has problems (always false for arrays & base types)
*/
public final boolean isHierarchyInconsistent() {
return (this.tagBits & TagBits.HierarchyHasProblems) != 0;
}
public boolean isInterface() {
return false;
}
public boolean isFunctionalInterface() {
return false;
}
/**
* Returns true if the current type denotes an intersection type: Number & Comparable<?>
*/
public boolean isIntersectionType() {
return false;
}
public final boolean isLocalType() {
return (this.tagBits & TagBits.IsLocalType) != 0;
}
public final boolean isMemberType() {
return (this.tagBits & TagBits.IsMemberType) != 0;
}
public final boolean isNestedType() {
return (this.tagBits & TagBits.IsNestedType) != 0;
}
public final boolean isNumericType() {
switch (this.id) {
case TypeIds.T_int:
case TypeIds.T_float:
case TypeIds.T_double:
case TypeIds.T_short:
case TypeIds.T_byte:
case TypeIds.T_long:
case TypeIds.T_char:
return true;
default:
return false;
}
}
//{ObjectTeams:
public boolean isTeam() {
return false;
}
public boolean isRole() {
return false;
}
// SH}
/**
* Returns true if the type is parameterized, e.g. List<String>.
* Note that some instances of ParameterizedTypeBinding have no arguments, like for non-generic members
* of a parameterized type. Use {@link #isParameterizedTypeWithActualArguments()} instead to find out.
*/
public final boolean isParameterizedType() {
return kind() == Binding.PARAMETERIZED_TYPE;
}
public boolean isIntersectionCastType() {
return false;
}
/**
* Returns true if the type is parameterized, e.g. List<String>
* Note that some instances of ParameterizedTypeBinding do answer false to {@link #isParameterizedType()}
* in case they have no arguments, like for non-generic members of a parameterized type.
* i.e. {@link #isParameterizedType()} is not equivalent to testing <code>type.kind() == Binding.PARAMETERIZED_TYPE</code>
*/
public final boolean isParameterizedTypeWithActualArguments() {
return (kind() == Binding.PARAMETERIZED_TYPE)
&& ((ParameterizedTypeBinding) this).arguments != null;
}
/**
* Returns true if the type is parameterized using its own type variables as arguments
*/
public boolean isParameterizedWithOwnVariables() {
if (kind() != Binding.PARAMETERIZED_TYPE)
return false;
ParameterizedTypeBinding paramType = (ParameterizedTypeBinding) this;
if (paramType.arguments == null)
return false;
TypeVariableBinding[] variables = erasure().typeVariables();
for (int i = 0, length = variables.length; i < length; i++) {
if (variables[i] != paramType.arguments[i])
return false;
}
ReferenceBinding enclosing = paramType.enclosingType();
if (enclosing != null && enclosing.erasure().isGenericType()
&& !enclosing.isParameterizedWithOwnVariables()) {
return false;
}
return true;
}
private boolean isProvableDistinctSubType(TypeBinding otherType) {
if (otherType.isInterface()) {
if (isInterface())
return false;
if (isArrayType()
|| ((this instanceof ReferenceBinding) && ((ReferenceBinding) this).isFinal())
|| (isTypeVariable() && ((TypeVariableBinding)this).superclass().isFinal())) {
return !isCompatibleWith(otherType);
}
return false;
} else {
if (isInterface()) {
if (otherType.isArrayType()
|| ((otherType instanceof ReferenceBinding) && ((ReferenceBinding) otherType).isFinal())
|| (otherType.isTypeVariable() && ((TypeVariableBinding)otherType).superclass().isFinal())) {
return !isCompatibleWith(otherType);
}
} else {
if (!isTypeVariable() && !otherType.isTypeVariable()) {
return !isCompatibleWith(otherType);
}
}
}
return false;
}
/**
* Returns true if a type is provably distinct from another one,
*/
public boolean isProvablyDistinct(TypeBinding otherType) {
/* With the hybrid 1.4/1.5+ projects modes, while establishing type equivalence, we need to
be prepared for a type such as Map appearing in one of three forms: As (a) a ParameterizedTypeBinding
e.g Map<String, String>, (b) as RawTypeBinding Map#RAW and finally (c) as a BinaryTypeBinding
When the usage of a type lacks type parameters, whether we land up with the raw form or not depends
on whether the underlying type was "seen to be" a generic type in the particular build environment or
not. See:
https://bugs.eclipse.org/bugs/show_bug.cgi?id=186565
https://bugs.eclipse.org/bugs/show_bug.cgi?id=328827
https://bugs.eclipse.org/bugs/show_bug.cgi?id=329588
*/
if (this == otherType)
return false;
if (otherType == null)
return true;
switch (kind()) {
case Binding.PARAMETERIZED_TYPE :
ParameterizedTypeBinding paramType = (ParameterizedTypeBinding) this;
switch(otherType.kind()) {
case Binding.PARAMETERIZED_TYPE :
ParameterizedTypeBinding otherParamType = (ParameterizedTypeBinding) otherType;
if (paramType.genericType() != otherParamType.genericType())
return true;
if (!paramType.isStatic()) { // static member types do not compare their enclosing
ReferenceBinding enclosing = enclosingType();
if (enclosing != null) {
ReferenceBinding otherEnclosing = otherParamType.enclosingType();
if (otherEnclosing == null) return true;
if ((otherEnclosing.tagBits & TagBits.HasDirectWildcard) == 0) {
if (enclosing.isProvablyDistinct(otherEnclosing)) return true; // https://bugs.eclipse.org/bugs/show_bug.cgi?id=302919
} else {
if (!enclosing.isEquivalentTo(otherParamType.enclosingType())) return true;
}
}
}
int length = paramType.arguments == null ? 0 : paramType.arguments.length;
TypeBinding[] otherArguments = otherParamType.arguments;
int otherLength = otherArguments == null ? 0 : otherArguments.length;
if (otherLength != length)
return true;
for (int i = 0; i < length; i++) {
if (paramType.arguments[i].isProvablyDistinctTypeArgument(otherArguments[i], paramType, i))
return true;
}
return false;
case Binding.GENERIC_TYPE :
if (paramType.genericType() != otherType)
return true;
if (!paramType.isStatic()) { // static member types do not compare their enclosing
ReferenceBinding enclosing = enclosingType();
if (enclosing != null) {
ReferenceBinding otherEnclosing = otherType.enclosingType();
if (otherEnclosing == null) return true;
if ((otherEnclosing.tagBits & TagBits.HasDirectWildcard) == 0) {
if (enclosing != otherEnclosing) return true;
} else {
if (!enclosing.isEquivalentTo(otherType.enclosingType())) return true;
}
}
}
length = paramType.arguments == null ? 0 : paramType.arguments.length;
otherArguments = otherType.typeVariables();
otherLength = otherArguments == null ? 0 : otherArguments.length;
if (otherLength != length)
return true;
for (int i = 0; i < length; i++) {
if (paramType.arguments[i].isProvablyDistinctTypeArgument(otherArguments[i], paramType, i))
return true;
}
return false;
case Binding.RAW_TYPE :
//{ObjectTeams: dependent types?
/* orig:
return erasure() != otherType.erasure();
case Binding.TYPE: // https://bugs.eclipse.org/bugs/show_bug.cgi?id=329588
return erasure() != otherType;
:giro */
return distinctRealTypes(erasure(), otherType.erasure());
case Binding.TYPE: // https://bugs.eclipse.org/bugs/show_bug.cgi?id=329588
return distinctRealTypes(erasure(), otherType);
// SH}
}
return true;
case Binding.RAW_TYPE : // dead code ??
switch(otherType.kind()) {
case Binding.GENERIC_TYPE :
case Binding.PARAMETERIZED_TYPE :
case Binding.RAW_TYPE :
case Binding.TYPE: // https://bugs.eclipse.org/bugs/show_bug.cgi?id=329588
//{ObjectTeams: dependent types?
/* orig:
return erasure() != otherType.erasure();
:giro */
return distinctRealTypes(erasure(), otherType.erasure());
// SH}
}
return true;
case Binding.TYPE: // https://bugs.eclipse.org/bugs/show_bug.cgi?id=329588
switch(otherType.kind()) {
case Binding.PARAMETERIZED_TYPE :
case Binding.RAW_TYPE :
return this != otherType.erasure();
}
break;
default :
break;
}
return true;
}
//{ObjectTeams: relax if at least one type is a dependent type binding:
boolean distinctRealTypes(TypeBinding one, TypeBinding two) {
if (one instanceof ReferenceBinding && two instanceof ReferenceBinding)
if (DependentTypeBinding.isDependentType(one) || DependentTypeBinding.isDependentType(two))
return ((ReferenceBinding)one).getRealType() != ((ReferenceBinding)two).getRealType();
return one != two;
}
// SH}
/**
* Returns false if two given types could not intersect as argument types:
* List<Throwable> & List<Runnable> --> false
* List<? extends Throwable> & List<? extends Runnable> --> true
* List<? extends String> & List<? extends Runnable> --> false
*/
private boolean isProvablyDistinctTypeArgument(TypeBinding otherArgument, final ParameterizedTypeBinding paramType, final int rank) {
if (this == otherArgument)
return false;
TypeBinding upperBound1 = null;
TypeBinding lowerBound1 = null;
ReferenceBinding genericType = paramType.genericType();
switch (kind()) {
case Binding.WILDCARD_TYPE :
WildcardBinding wildcard = (WildcardBinding) this;
switch (wildcard.boundKind) {
case Wildcard.EXTENDS:
upperBound1 = wildcard.bound;
break;
case Wildcard.SUPER:
lowerBound1 = wildcard.bound;
break;
case Wildcard.UNBOUND:
return false;
}
break;
case Binding.INTERSECTION_TYPE :
break;
case Binding.TYPE_PARAMETER :
final TypeVariableBinding variable = (TypeVariableBinding) this;
if (variable.isCapture()) {
CaptureBinding capture = (CaptureBinding) variable;
switch (capture.wildcard.boundKind) {
case Wildcard.EXTENDS:
upperBound1 = capture.wildcard.bound;
break;
case Wildcard.SUPER:
lowerBound1 = capture.wildcard.bound;
break;
case Wildcard.UNBOUND:
return false;
}
break;
}
if (variable.firstBound == null) // unbound variable
return false;
TypeBinding eliminatedType = Scope.convertEliminatingTypeVariables(variable, genericType, rank, null);
switch (eliminatedType.kind()) {
case Binding.WILDCARD_TYPE :
case Binding.INTERSECTION_TYPE :
wildcard = (WildcardBinding) eliminatedType;
switch (wildcard.boundKind) {
case Wildcard.EXTENDS:
upperBound1 = wildcard.bound;
break;
case Wildcard.SUPER:
lowerBound1 = wildcard.bound;
break;
case Wildcard.UNBOUND:
return false;
}
break;
}
break;
}
TypeBinding upperBound2 = null;
TypeBinding lowerBound2 = null;
switch (otherArgument.kind()) {
case Binding.WILDCARD_TYPE :
WildcardBinding otherWildcard = (WildcardBinding) otherArgument;
switch (otherWildcard.boundKind) {
case Wildcard.EXTENDS:
upperBound2 = otherWildcard.bound;
break;
case Wildcard.SUPER:
lowerBound2 = otherWildcard.bound;
break;
case Wildcard.UNBOUND:
return false;
}
break;
case Binding.INTERSECTION_TYPE :
break;
case Binding.TYPE_PARAMETER :
TypeVariableBinding otherVariable = (TypeVariableBinding) otherArgument;
if (otherVariable.isCapture()) {
CaptureBinding otherCapture = (CaptureBinding) otherVariable;
switch (otherCapture.wildcard.boundKind) {
case Wildcard.EXTENDS:
upperBound2 = otherCapture.wildcard.bound;
break;
case Wildcard.SUPER:
lowerBound2 = otherCapture.wildcard.bound;
break;
case Wildcard.UNBOUND:
return false;
}
break;
}
if (otherVariable.firstBound == null) // unbound variable
return false;
TypeBinding otherEliminatedType = Scope.convertEliminatingTypeVariables(otherVariable, genericType, rank, null);
switch (otherEliminatedType.kind()) {
case Binding.WILDCARD_TYPE :
case Binding.INTERSECTION_TYPE :
otherWildcard = (WildcardBinding) otherEliminatedType;
switch (otherWildcard.boundKind) {
case Wildcard.EXTENDS:
upperBound2 = otherWildcard.bound;
break;
case Wildcard.SUPER:
lowerBound2 = otherWildcard.bound;
break;
case Wildcard.UNBOUND:
return false;
}
break;
} break;
}
if (lowerBound1 != null) {
if (lowerBound2 != null) {
return false; // Object could always be a candidate
} else if (upperBound2 != null) {
if (lowerBound1.isTypeVariable() || upperBound2.isTypeVariable()) {
return false;
}
return !lowerBound1.isCompatibleWith(upperBound2);
} else {
if (lowerBound1.isTypeVariable() || otherArgument.isTypeVariable()) {
return false;
}
return !lowerBound1.isCompatibleWith(otherArgument);
}
} else if (upperBound1 != null) {
if (lowerBound2 != null) {
return !lowerBound2.isCompatibleWith(upperBound1);
} else if (upperBound2 != null) {
return upperBound1.isProvableDistinctSubType(upperBound2)
&& upperBound2.isProvableDistinctSubType(upperBound1);
} else {
return otherArgument.isProvableDistinctSubType(upperBound1);
}
} else {
if (lowerBound2 != null) {
if (lowerBound2.isTypeVariable() || isTypeVariable()) {
return false;
}
return !lowerBound2.isCompatibleWith(this);
} else if (upperBound2 != null) {
return isProvableDistinctSubType(upperBound2);
} else {
return true; // ground types should have been the same
}
}
}
public final boolean isRawType() {
return kind() == Binding.RAW_TYPE;
}
/**
* JLS(3) 4.7.
* Note: Foo<?>.Bar is also reifiable
*/
public boolean isReifiable() {
TypeBinding leafType = leafComponentType();
if (!(leafType instanceof ReferenceBinding))
return true;
ReferenceBinding current = (ReferenceBinding) leafType;
do {
switch (current.kind()) {
case Binding.TYPE_PARAMETER:
case Binding.WILDCARD_TYPE:
case Binding.INTERSECTION_TYPE:
case Binding.GENERIC_TYPE:
return false;
case Binding.PARAMETERIZED_TYPE:
if (current.isBoundParameterizedType())
return false;
break;
case Binding.RAW_TYPE:
return true;
}
if (current.isStatic()) {
return true;
}
if (current.isLocalType()) {
LocalTypeBinding localTypeBinding = (LocalTypeBinding) current.erasure();
MethodBinding enclosingMethod = localTypeBinding.enclosingMethod;
if (enclosingMethod != null && enclosingMethod.isStatic()) {
return true;
}
}
} while ((current = current.enclosingType()) != null);
return true;
}
/**
* Returns true if a given type may be thrown
*/
public boolean isThrowable() {
return false;
}
// JLS3: 4.5.1.1
public boolean isTypeArgumentContainedBy(TypeBinding otherType) {
//{ObjectTeams: only slightly weaker form of identity:
/* orig:
if (this == otherType)
:giro */
if (RoleTypeBinding.eq(this, otherType))
// SH}
return true;
switch (otherType.kind()) {
// handle captured wildcards.
case Binding.TYPE_PARAMETER: {
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=347426
if (!isParameterizedType() || !otherType.isCapture()) {
return false;
}
CaptureBinding capture = (CaptureBinding) otherType;
WildcardBinding wildcard = capture.wildcard;
TypeBinding upperBound = null;
TypeBinding [] otherBounds = null;
switch (wildcard.boundKind) {
case Wildcard.SUPER:
return false; // T super syntax isn't allowed, impossible capture.
case Wildcard.UNBOUND:
TypeVariableBinding variable = wildcard.genericType.typeVariables()[wildcard.rank];
upperBound = variable.upperBound();
otherBounds = variable.boundsCount() > 1 ? variable.otherUpperBounds() : null;
break;
case Wildcard.EXTENDS:
upperBound = wildcard.bound;
otherBounds = wildcard.otherBounds;
break;
}
// Given class A<T extends B<?>>, A<?> cannot be the universe of all parameterizations of A
if (upperBound.id == TypeIds.T_JavaLangObject && otherBounds == null) {
return false; // but given class A<T>, A<?> stays an unbounded wildcard, see https://bugs.eclipse.org/bugs/show_bug.cgi?id=348956
}
otherType = capture.environment.createWildcard(null, 0, upperBound, otherBounds, Wildcard.EXTENDS);
return isTypeArgumentContainedBy(otherType);
}
// allow wildcard containment
case Binding.WILDCARD_TYPE:
case Binding.INTERSECTION_TYPE:
TypeBinding lowerBound = this;
TypeBinding upperBound = this;
switch (kind()) {
case Binding.WILDCARD_TYPE:
case Binding.INTERSECTION_TYPE:
WildcardBinding wildcard = (WildcardBinding) this;
switch (wildcard.boundKind) {
case Wildcard.EXTENDS:
if (wildcard.otherBounds != null) // intersection type
break;
upperBound = wildcard.bound;
lowerBound = null;
break;
case Wildcard.SUPER:
upperBound = wildcard;
lowerBound = wildcard.bound;
break;
case Wildcard.UNBOUND:
upperBound = wildcard;
lowerBound = null;
}
break;
case Binding.TYPE_PARAMETER:
if (isCapture()) {
CaptureBinding capture = (CaptureBinding) this;
if (capture.lowerBound != null)
lowerBound = capture.lowerBound;
}
}
WildcardBinding otherWildcard = (WildcardBinding) otherType;
if (otherWildcard.otherBounds != null)
return false; // not a true wildcard (intersection type)
TypeBinding otherBound = otherWildcard.bound;
switch (otherWildcard.boundKind) {
case Wildcard.EXTENDS:
if (otherBound == this)
return true; // ? extends T <= ? extends ? extends T
if (upperBound == null)
return false;
TypeBinding match = upperBound.findSuperTypeOriginatingFrom(otherBound);
if (match != null && (match = match.leafComponentType()).isRawType()) {
return match == otherBound.leafComponentType(); // forbide: Collection <= ? extends Collection<?>
// forbide: Collection[] <= ? extends Collection<?>[]
}
return upperBound.isCompatibleWith(otherBound);
case Wildcard.SUPER:
if (otherBound == this)
return true; // ? super T <= ? super ? super T
if (lowerBound == null)
return false;
match = otherBound.findSuperTypeOriginatingFrom(lowerBound);
if (match != null && (match = match.leafComponentType()).isRawType()) {
return match == lowerBound.leafComponentType(); // forbide: Collection <= ? super Collection<?>
// forbide: Collection[] <= ? super Collection<?>[]
}
return otherBound.isCompatibleWith(lowerBound);
case Wildcard.UNBOUND:
default:
return true;
}
// allow List<?> to match List<? extends Object> (and reciprocally)
case Binding.PARAMETERIZED_TYPE:
if (!isParameterizedType())
return false;
ParameterizedTypeBinding paramType = (ParameterizedTypeBinding) this;
ParameterizedTypeBinding otherParamType = (ParameterizedTypeBinding) otherType;
if (paramType.actualType() != otherParamType.actualType())
return false;
if (!paramType.isStatic()) { // static member types do not compare their enclosing
ReferenceBinding enclosing = enclosingType();
if (enclosing != null) {
ReferenceBinding otherEnclosing = otherParamType .enclosingType();
if (otherEnclosing == null)
return false;
if ((otherEnclosing.tagBits & TagBits.HasDirectWildcard) == 0) {
if (enclosing != otherEnclosing)
return false;
} else {
if (!enclosing.isEquivalentTo(otherParamType.enclosingType()))
return false;
}
}
}
int length = paramType.arguments == null ? 0 : paramType.arguments.length;
TypeBinding[] otherArguments = otherParamType.arguments;
int otherLength = otherArguments == null ? 0 : otherArguments.length;
if (otherLength != length)
return false;
nextArgument: for (int i = 0; i < length; i++) {
TypeBinding argument = paramType.arguments[i];
TypeBinding otherArgument = otherArguments[i];
if (argument == otherArgument)
continue nextArgument;
int kind = argument.kind();
if (otherArgument.kind() != kind)
return false;
switch (kind) {
case Binding.PARAMETERIZED_TYPE:
if (argument.isTypeArgumentContainedBy(otherArgument)) // recurse
continue nextArgument;
break;
case Binding.WILDCARD_TYPE:
case Binding.INTERSECTION_TYPE:
WildcardBinding wildcard = (WildcardBinding) argument;
otherWildcard = (WildcardBinding) otherArgument;
switch (wildcard.boundKind) {
case Wildcard.EXTENDS:
// match "? extends <upperBound>" with "?"
if (otherWildcard.boundKind == Wildcard.UNBOUND
&& wildcard.bound == wildcard.typeVariable().upperBound())
continue nextArgument;
break;
case Wildcard.SUPER:
break;
case Wildcard.UNBOUND:
// match "?" with "? extends <upperBound>"
if (otherWildcard.boundKind == Wildcard.EXTENDS
&& otherWildcard.bound == otherWildcard.typeVariable().upperBound())
continue nextArgument;
break;
}
break;
}
return false;
}
return true;
}
// (? super Object) <= Object
if (otherType.id == TypeIds.T_JavaLangObject) {
switch (kind()) {
case Binding.WILDCARD_TYPE:
WildcardBinding wildcard = (WildcardBinding) this;
if (wildcard.boundKind == Wildcard.SUPER && wildcard.bound.id == TypeIds.T_JavaLangObject) {
return true;
}
break;
}
}
return false;
}
/**
* Returns true if the type was declared as a type variable
*/
public boolean isTypeVariable() {
return false;
}
/**
* Returns true if wildcard type of the form '?' (no bound)
*/
public boolean isUnboundWildcard() {
return false;
}
/**
* Returns true if the type is a subclass of java.lang.Error or java.lang.RuntimeException
*/
public boolean isUncheckedException(boolean includeSupertype) {
return false;
}
/**
* Returns true if the type is a wildcard
*/
public boolean isWildcard() {
return false;
}
/* API
* Answer the receiver's binding type from Binding.BindingID.
*/
public int kind() {
return Binding.TYPE;
}
public TypeBinding leafComponentType() {
return this;
}
/**
* Meant to be invoked on compatible types, to figure if unchecked conversion is necessary
*/
public boolean needsUncheckedConversion(TypeBinding targetType) {
if (this == targetType)
return false;
targetType = targetType.leafComponentType();
if (!(targetType instanceof ReferenceBinding))
return false;
TypeBinding currentType = leafComponentType();
TypeBinding match = currentType.findSuperTypeOriginatingFrom(targetType);
if (!(match instanceof ReferenceBinding))
return false;
ReferenceBinding compatible = (ReferenceBinding) match;
while (compatible.isRawType()) {
if (targetType.isBoundParameterizedType())
return true;
if (compatible.isStatic())
break;
if ((compatible = compatible.enclosingType()) == null)
break;
if ((targetType = targetType.enclosingType()) == null)
break;
}
return false;
}
/** Answer a readable name (for error reporting) that includes nullness type annotations. */
public char[] nullAnnotatedReadableName(LookupEnvironment env, boolean shortNames) /* e.g.: java.lang.Object @o.e.j.a.NonNull[] */ {
if (shortNames)
return shortReadableName();
else
return readableName();
}
/**
* Returns the orignal generic type instantiated by the receiver type, or itself if not.
* This is similar to erasure process, except it doesn't erase type variable, wildcard, intersection types etc...
*/
public TypeBinding original() {
switch(kind()) {
case Binding.PARAMETERIZED_TYPE :
case Binding.RAW_TYPE :
case Binding.ARRAY_TYPE :
return erasure();
default :
return this;
}
}
/**
* Answer the qualified name of the receiver's package separated by periods
* or an empty string if its the default package.
*
* For example, {java.util}.
*/
public char[] qualifiedPackageName() {
PackageBinding packageBinding = getPackage();
return packageBinding == null
|| packageBinding.compoundName == CharOperation.NO_CHAR_CHAR ? CharOperation.NO_CHAR
: packageBinding.readableName();
}
/**
* Answer the source name for the type.
* In the case of member types, as the qualified name from its top level type.
* For example, for a member type N defined inside M & A: "A.M.N".
*/
public abstract char[] qualifiedSourceName();
/**
* Answer the receiver classfile signature.
* Arrays & base types do not distinguish between signature() & constantPoolName().
* NOTE: This method should only be used during/after code gen.
*/
public char[] signature() {
return constantPoolName();
}
public abstract char[] sourceName();
//{ObjectTeams: Raw type name. Not beautified.
public char[] internalName() {
return sourceName();
}
// SH}
public void swapUnresolved(UnresolvedReferenceBinding unresolvedType,
ReferenceBinding resolvedType, LookupEnvironment environment) {
// subclasses must override if they wrap another type binding
}
public TypeVariableBinding[] typeVariables() {
return Binding.NO_TYPE_VARIABLES;
}
//{ObjectTeams: value parameters
/** Return the synthetic arguments representing value parameters.
* Note that each synthetic argument refers to the matchingField (final)
* by which client code can access the value parameter.
*/
public SyntheticArgumentBinding[] valueParamSynthArgs() {
return Binding.NO_SYNTH_ARGUMENTS;
}
public DependentTypeBinding asPlainDependentType() {
return null; // is not a dependent type
}
// SH}
/**
* Return the single abstract method of a functional interface, or null, if the receiver is not a functional interface as defined in JLS 9.8.
* @param scope scope
*
* @return The single abstract method of a functional interface, or null, if the receiver is not a functional interface.
*/
public MethodBinding getSingleAbstractMethod(Scope scope) {
return null;
}
public ReferenceBinding[] getIntersectingTypes() {
return null;
}
}