[PATCH] 8074570: Javac does not get membership right when it comes to erased supertypes

bsrbnd bsrbnd at gmail.com
Sat Aug 22 11:51:44 UTC 2015


I think you're right.
Jls example 4.8-2 demonstrates clearly the behavior of javac:
"The raw type RawMembers inherits iterator() from Collection, the
erasure of Collection<String>, which means that the return type of
iterator() in RawMembers is Iterator."

Nevertheless, without knowing all the compatibility reasons behind
this, I think it could be meaningful to keep unrelated (to the raw
type) used parameters and replace all (related or not) unused
parameters with "Object" the same way it is already done for the
classes and interfaces members of a raw type (and his
super-classes/interfaces members).

But, as you said, it will take time to improve this.
Moreover, as written in jls 4.8, "The use of raw types is allowed only
as a concession to compatibility of legacy code. [...] It is possible
that future versions of Java programming language will disallow the
use of raw types".

Regards,
bsrbnd

2015-08-20 2:57 GMT+02:00 Maurizio Cimadamore <maurizio.cimadamore at oracle.com>:
> 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