/** * Compare to see if the argument <code>argType</code> passed to the method matches the type of * the corresponding parameter. The simplest case is when both are equal. * * <p>This is a conservative comparison - returns true if it cannot decide. If the parameter type * is a type variable (e.g. <code>T</code>) then we don't know enough (yet) to decide if they do * not match so return true. * * @param ignoreBaseType TODO */ private IncompatibleTypes compareTypes( Type expectedType, Type actualType, boolean ignoreBaseType) { // XXX equality not implemented for GenericObjectType // if (parmType.equals(argType)) return true; if (expectedType == actualType) return IncompatibleTypes.SEEMS_OK; // Compare type signatures instead String expectedString = GenericUtilities.getString(expectedType); String actualString = GenericUtilities.getString(actualType); if (expectedString.equals(actualString)) return IncompatibleTypes.SEEMS_OK; if (expectedType.equals(Type.OBJECT)) return IncompatibleTypes.SEEMS_OK; // if either type is java.lang.Object, then automatically true! // again compare strings... String objString = GenericUtilities.getString(Type.OBJECT); if (expectedString.equals(objString)) { return IncompatibleTypes.SEEMS_OK; } // get a category for each type TypeCategory expectedCat = GenericUtilities.getTypeCategory(expectedType); TypeCategory argCat = GenericUtilities.getTypeCategory(actualType); if (actualString.equals(objString) && expectedCat == TypeCategory.TYPE_VARIABLE) { return IncompatibleTypes.SEEMS_OK; } if (ignoreBaseType) { if (expectedCat == TypeCategory.PARAMETERIZED && argCat == TypeCategory.PARAMETERIZED) { GenericObjectType parmGeneric = (GenericObjectType) expectedType; GenericObjectType argGeneric = (GenericObjectType) actualType; return compareTypeParameters(parmGeneric, argGeneric); } return IncompatibleTypes.SEEMS_OK; } if (actualType.equals(Type.OBJECT) && expectedCat == TypeCategory.ARRAY_TYPE) return IncompatibleTypes.ARRAY_AND_OBJECT; // -~- plain objects are easy if (expectedCat == TypeCategory.PLAIN_OBJECT_TYPE && argCat == TypeCategory.PLAIN_OBJECT_TYPE) return IncompatibleTypes.getPriorityForAssumingCompatible(expectedType, actualType, false); if (expectedCat == TypeCategory.PARAMETERIZED && argCat == TypeCategory.PLAIN_OBJECT_TYPE) return IncompatibleTypes.getPriorityForAssumingCompatible( (GenericObjectType) expectedType, actualType); if (expectedCat == TypeCategory.PLAIN_OBJECT_TYPE && argCat == TypeCategory.PARAMETERIZED) return IncompatibleTypes.getPriorityForAssumingCompatible( (GenericObjectType) actualType, expectedType); // -~- parmType is: "? extends Another Type" OR "? super Another Type" if (expectedCat == TypeCategory.WILDCARD_EXTENDS || expectedCat == TypeCategory.WILDCARD_SUPER) return compareTypes( ((GenericObjectType) expectedType).getExtension(), actualType, ignoreBaseType); // -~- Not handling type variables if (expectedCat == TypeCategory.TYPE_VARIABLE || argCat == TypeCategory.TYPE_VARIABLE) return IncompatibleTypes.SEEMS_OK; // -~- Array Types: compare dimensions, then base type if (expectedCat == TypeCategory.ARRAY_TYPE && argCat == TypeCategory.ARRAY_TYPE) { ArrayType parmArray = (ArrayType) expectedType; ArrayType argArray = (ArrayType) actualType; if (parmArray.getDimensions() != argArray.getDimensions()) return IncompatibleTypes.ARRAY_AND_NON_ARRAY; return compareTypes(parmArray.getBasicType(), argArray.getBasicType(), ignoreBaseType); } // If one is an Array Type and the other is not, then they // are incompatible. (We already know neither is java.lang.Object) if (expectedCat == TypeCategory.ARRAY_TYPE ^ argCat == TypeCategory.ARRAY_TYPE) { return IncompatibleTypes.ARRAY_AND_NON_ARRAY; } // -~- Parameter Types: compare base type then parameters if (expectedCat == TypeCategory.PARAMETERIZED && argCat == TypeCategory.PARAMETERIZED) { GenericObjectType parmGeneric = (GenericObjectType) expectedType; GenericObjectType argGeneric = (GenericObjectType) actualType; // base types should be related { IncompatibleTypes result = compareTypes(parmGeneric.getObjectType(), argGeneric.getObjectType(), ignoreBaseType); if (!result.equals(IncompatibleTypes.SEEMS_OK)) return result; } return compareTypeParameters(parmGeneric, argGeneric); // XXX More to come } // If one is a Parameter Type and the other is not, then they // are incompatible. (We already know neither is java.lang.Object) if (false) { // not true. Consider class Foo extends ArrayList<String> if (expectedCat == TypeCategory.PARAMETERIZED ^ argCat == TypeCategory.PARAMETERIZED) { return IncompatibleTypes.SEEMS_OK; // fix this when we know what // we are doing here } } // -~- Wildcard e.g. List<*>.contains(...) if (expectedCat == TypeCategory.WILDCARD) // No Way to know return IncompatibleTypes.SEEMS_OK; // -~- Non Reference types // if ( parmCat == TypeCategory.NON_REFERENCE_TYPE || // argCat == TypeCategory.NON_REFERENCE_TYPE ) if (expectedType instanceof BasicType || actualType instanceof BasicType) { // this should not be possible, compiler will complain (pre 1.5) // or autobox primitive types (1.5 +) throw new IllegalArgumentException( "checking for compatibility of " + expectedType + " with " + actualType); } return IncompatibleTypes.SEEMS_OK; }