[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