Community
Participate
Working Groups
I20041208-1200 I found out why the Javadoc of getErasure() of ITypeBinding and IMethodBinding contained: * Note: the erasure link is not a general back-link between the members * of a generic type instance and the corresponding members of the * generic type. (removed on my request in bug 79136). The upcoming JLS3 defines erasure in '4.6 Type Erasure': [..] - The erasure of a parameterized type (§4.5) T<T1, ... ,Tn> is |T|. [..] - The erasure of a method signature s is a signature consisting of the same name as s, and the erasures of all the formal parameter types given in s. Note that the erasure of T<T1, ... ,Tn> does not contain any type parameters or arguments. Section '4.8 Raw Types' explicitly says: "To facilitate interfacing with non-generic legacy code, it is also possible to use as a type the erasure (§4.6) of a parameterized type (§4.5). Such a type is called a raw type.[..]". From this perspective, the erasure of a type/method is indeed not the generic version, but the raw version. In order to conform to the specs, we should consider a) renaming the current getErasure() into getGenericType/Method(), and b) introducing new methods getErasure(), which return the raw binding of the receiver (see also bugs 77360, 40096).
I agree that getErasure() is bad choice of name given the way "erasure" is defined in JLS3. I've done part (a): - renamed ITypeBinding.getErasure() to getGenericType() - deprecated ITypeBinding.getErasure() - renamed IMethodBinding.getErasure() to getGenericMethod() - deprecated IMethodBinding.getErasure() - updated ASTConverter15Test Both deprecated methods are part of J2SE5 effort, and should be deleted before 3.1M5 once clients are no longer using them. re: part (b). As discussed in bug 40096, the binding API does not provide operations that would require creating new bindings. Olivier, is there a binding for the raw type at the compiler level? I.e., would it be possible to provide a method that returned the corresponding raw type?
Markus, can you please adjust the callers of getErasure() in JDT/UI accordingly.
I guess it is possible to get the corresponding raw type. So we need to decide if we change the behavior of the method getErasure() or if we add a new method.
Contrary to my initial suggestion, I would not call the method that returns the raw type getErasure(). getRawType() would be more in-line with getGenericType() and the checks isRawType() and isGenericType().
I'd like to do neither. A raw type binding is a binding for a particular kind of *reference* to a generic type. Markus, Do you have a particular usecase for providing a navigation from a generic type to the erasure type?
What about 'getErasure()' on type variables? For <A extends Vector> isn't 'Vector' the _erasure_? 'getGenericType()' doesn't seem to apply here.
I didn't find a way to get a raw type from any parameterized type binding on the compiler side. Jim, what action do you want to do? Philippe, any comment?
Jim, I reassign to you as long as the API side is not complete.
Jeem, we had a long discussion about this here in ZRH and with Philippe. Our outcome was as follows: - we need a method ITypeBinding#getErasureType() to implement signature comparison. We agreed that this method might return the generic type instead of the raw type, when the compiler doesn't have the raw type. The behaviour should be consistent though. - we need a method to navigate from a parameterized type to a generic type. This can either be getGenericType or a method getTypeDeclaration. The advantage of the second one is that it can return something for all type bindings. - IMethodBinding#getErasureMethod should be removed. Instead a method getGeneric Method or getMethodDeclaration should be added. Jeem, what do you think ?
The changes I made in comment #1 address the last 2 bullets in comment #9: - ITypeBinding.getGenericType() navigates from a parameterized type to a generic type. It's spec'd to return something for all type bindings. - IMethodBinding.getGenericMethod() replaced IMethodBinding.getErasureMethod(). For the first bullet, it would be weird for a method to return the raw type in some cases and the generic type if the raw type happened to be unavailable. How about this instead: getRawTypeIfAvailable() returns the raw type is it happens to be available, otherwise null. A client could use getRawTypeIfAvailable() != null ? getRawTypeIfAvailable() : getGenericType() to implement signature comparison.
Jeem, I introduced some confusion here, sorry. I didn't mean that getErasure sometimes returns the raw and sometimes the generic type. It should always return the same kind of type. All I tried to say was that we prefer getting the raw type (since that's what the spec is saying) and if this isn't possible, the generic type. Regarding getGenericType returning something all the time. This seems wired from an API stand point since 'String'.getGenericType().isGenericType() == false. IMO we should still offer a method getErasure() (even if it doesn't fully follow the spec) since that's what clients want to do. Calling getGenericType() instead of getErasure() makes code harder to understand. So prefer the following methods: ITypeBinding#getErasure(): return something for every kind of type. For parameterized types and generic types this will be the generic type. ITypeBinding#getTypeDeclaration(): although this method will return the same as getErasure() (because we can return raw types here) I would prefer having this. In client code it is a difference navigating to something or taking the erasure. IMethodBinding#getTypeDeclaration(): same as for types.
Note: there should be a difference between getTypeDeclaration() and getErasure(): * ITypeBinding#getTypeDeclaration(): isGenericType -> isGenericType (identical) isParameterizedType -> isGenericType isRawType -> isGenericType isWildcardType -> isWildcardType (identical) isTypeVariable -> isTypeVariable (identical) nongeneric -> nongeneric (identical) * ITypeBinding#getErasure(): isGenericType -> isGenericType (identical) isParameterizedType -> isGenericType isRawType -> isGenericType (identical) isWildcardType -> '? extends': bound; '?' and '? super': Object isTypeVariable -> erasure of leftmost bound nongeneric -> nongeneric (identical) * IMethodBinding#getMethodDeclaration(): isGenericMethod -> isGenericMethod (identical) isParameterizedMethod -> isGenericMethod isRawMethod -> isGenericMethod nongeneric -> nongeneric (identical) * IMethodBinding#getErasure(): Remove this method. The correct result for IMethodBinding#getErasure() would be a method binding with all parameter and return types erased by ITypeBinding#getErasure(). But I don't think it's possible for the compiler to return such a method binding.
Martin, Your table is very helpful. For ITypeBinding.getErasure(), I assume you meant to say: isRawType -> isRawType (identical)
[Martin -> Markus ;-] Oops, that was a typo. I meant: * ITypeBinding#getErasure(): isRawType -> isGenericType The erasure as defined by the table above will be used to "normalize" a type binding to something that's written to the classfile. We will use getErasure() to compare such normalized references in order to e.g. find out whether two types will be erased to the same entity in the classfile. To be consistent for all kinds of generic/parameterized/raw types, getErasure() should always return the same kind of binding (which will be a *generic* type, since comment 7 indicated that it is difficult to get the raw type in all cases). Sidenote: The problem we were facing here (whether the return type of getErasure() should be a raw or a generic type), is really a question of different models. The erasure process is a transformation from a compiler-world ITypeBinding to a classfile-world erased type. Since we don't have entities for these classfile types, we try to get a useful result in terms of compiler-world ITypeBindings. For this mapping back to the compiler-world, we are actually free to choose between raw and generic types. Both are +/- equally "right" or "wrong".
Here are specs for ITypeBinding.getTypeDeclaration() and getErasure(). Let me know if these are ok. /** * Returns the binding for the type declaration corresponding to this type * binding. For parameterized types ({@link #isParameterizedType()}) * and raw types ({@link #isRawType()}), this method returns the binding * for the corresponding generic type. For other type bindings, this * returns the same binding. * <p> * Note: Support for new language features proposed for the upcoming 1.5 * release of J2SE is tentative and subject to change. * </p> * * @return the generic type binding * @since 3.1 */ public ITypeBinding getTypeDeclaration(); /** * Returns the erasure of this type binding. * <ul> * <li>For parameterized types ({@link #isParameterizedType()}) * - returns the binding for the corresponding generic type.</li> * <li>For raw types ({@link #isRawType()}) * - returns the identical binding.</li> * <li>For wildcard types ({@link #isWildcardType()}) * - returns the binding for the upper bound if it has one and * java.lang.Object in other cases. * </li> * <li>For type variables ({@link #isTypeVariable()}) * - returns the binding for the erasure of the leftmost bound * if it has bounds and java.lang.Object if it does not.</li> * <li>For all other type bindings - returns the identical binding.</li> * </ul> * <p> * Note: Support for new language features proposed for the upcoming 1.5 * release of J2SE is tentative and subject to change. * </p> * * @return the erasure type binding * @since 3.0 */ public ITypeBinding getErasure();
That's probably a typo: * <li>For raw types ({@link #isRawType()}) * - returns the identical binding.</li>
I've correct it to read: * <li>For raw types ({@link #isRawType()}) * - returns the binding for the corresponding generic type.</li>
Olivier, Back over to you.
I fully agree with the latest specs as committed in HEAD.
Added implementation that matches the released API. Added tests ASTConvert15Test#test0110() to test0125().
Verified in I20050214-0927