[PATCH] 8074570: Javac does not get membership right when it comes to erased supertypes
Maurizio Cimadamore
maurizio.cimadamore at oracle.com
Thu Aug 20 00:57:54 UTC 2015
Hi,
I think javac is behaving according to the JLS - section 4.8 (raw types):
"The superclasses (respectively, superinterfaces) of a raw type are the
erasures of the superclasses (superinterfaces) of any of the
parameterizations of the generic type. "
This seems to imply that the supertype of Sub (raw) is just Sup; I agree
this is confusing and a lot of people trip over this - but that's what
the spec mandates. That said, we are aware of this and we'd like to
improve over this - but it will take a while to figure out a plausible
compatibility story.
Maurizio
On 19/08/15 18:33, bsrbnd wrote:
> Hi,
>
> As explained in issue 8074570 the following code doesn't compile
> because javac looses all type parameters when it comes to an erased
> supertype:
>
> interface Sup<X> {
> boolean m(X x);
> }
>
> interface Sub<X> extends Sup<String> {
> boolean m(String s);
> }
>
> class Test {
> void test() {
> Sub s = new Sub() { // new Sub<Void> compiles..
> @Override
> public boolean m(String o) {return true;}
> };
> }
> }
>
> In this example, when all type parameters are erased, interface "Sup"
> defines abstract method "boolean m(Object x)" which is not overriden
> in our anonymous class.
> If you give a type parameter to "Sub" (for example: new Sub<Void>()
> {...}), all compiles fine because type parameters are not erased.
>
> The problem occures in Types.memberType(Type, Symbol) when javac
> searches for an implementation of Sup<X>.m(X x).
> The call to Types.asOuterSuper(Type, Symbol) erases type parameters.
>
> The following patch replaces undefined type parameters with Object
> parameters instead of erasing them in Types.supertype(Type) and
> Types.interfaces(Type).
>
> I'm not sure if this is very clean, but it seems that it corrects the problem.
> It is also possible that this fix is too global and could be made more
> locally to avoid side effects.
>
> diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java
> b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java
> --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java
> +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java
> @@ -2211,6 +2211,23 @@
> public List<Type> erasureRecursive(List<Type> ts) {
> return erasure.visit(ts, true);
> }
> +
> + private List<Type> erasureWithObjects(List<Type> ts, List<Type> formals) {
> + Type[] objectParams = new Type[formals.length()];
> + for (int i=0; i<formals.length(); i++) {
> + objectParams[i] = syms.objectType;
> + }
> + List<Type> subt = subst(ts, formals, List.from(objectParams));
> + return subt;
> + }
> + private Type erasureWithObjects(Type t, List<Type> formals) {
> + Type[] objectParams = new Type[formals.length()];
> + for (int i=0; i<formals.length(); i++) {
> + objectParams[i] = syms.objectType;
> + }
> + Type subt = subst(t, formals, List.from(objectParams));
> + return subt;
> + }
> // </editor-fold>
>
> // <editor-fold defaultstate="collapsed" desc="makeIntersectionType">
> @@ -2281,7 +2298,7 @@
> List<Type> actuals = classBound(t).allparams();
> List<Type> formals = t.tsym.type.allparams();
> if (t.hasErasedSupertypes()) {
> - t.supertype_field = erasureRecursive(supertype);
> + t.supertype_field =
> erasureWithObjects(supertype, formals);
> } else if (formals.nonEmpty()) {
> t.supertype_field = subst(supertype,
> formals, actuals);
> }
> @@ -2362,7 +2379,7 @@
> List<Type> actuals = t.allparams();
> List<Type> formals = t.tsym.type.allparams();
> if (t.hasErasedSupertypes()) {
> - t.interfaces_field = erasureRecursive(interfaces);
> + t.interfaces_field =
> erasureWithObjects(interfaces, formals);
> } else if (formals.nonEmpty()) {
> t.interfaces_field = subst(interfaces,
> formals, actuals);
> }
>
>
> Regards,
>
> bsrbnd
More information about the compiler-dev
mailing list