Possible regression involving inferred generic types

Alex Buckley alex.buckley at oracle.com
Wed Nov 6 11:32:31 PST 2013


Thanks Vicente. I believe you actually updated JDK-7144506, not 
JDK-7115044 (the master issue for lambda expressions). BTW the title for 
JDK-7144506 is inscrutable, so I suggest including a heading in the 
comment for the Docs team to use. Something like "Tighter handling of 
raw types means more return types are erased". (Please note the phrase 
"generic method" should not appear - people seem to love using it when 
method invocation meets parameterized types, but it is not relevant here.)

Alex

On 11/6/2013 2:47 AM, Vicente-Arturo Romero-Zaldivar wrote:
> Hi Alex,
>
> Thanks for the links, I have updated JDK-7115044 as you suggested,
>
> Vicente
>
> On 04/11/13 18:53, Alex Buckley wrote:
>> Hi Vicente,
>>
>> Thanks for identifying the JBS issue which describes the change.
>>
>> If javac in JDK7 compiled this illegal code, and javac in JDK8 rejects
>> this illegal code, then the JBS issue should be documented as a source
>> compatibility issue in the JDK8 Release Notes. As examples, see the
>> "Tools" items in the JDK7 Release Notes at [1]. This is exactly the
>> place to identify changes in javac made for solid conformance reasons
>> which will nevertheless confuse legions of programmers.
>>
>> So, please take over JDK-7115044, add the label "release-note=yes",
>> and add a comment showing ReproOne.java with a brief description.
>>
>> Alex
>>
>> [1]
>> http://www.oracle.com/technetwork/java/javase/compatibility-417013.html#jdk7
>>
>>
>> On 11/4/2013 7:10 AM, Vicente-Arturo Romero-Zaldivar wrote:
>>> Hi Liam,
>>>
>>> I have been investigating the issue you reported. The fix that changed
>>> javac's behavior is deep in current javac 8 repo, see [1], the original
>>> bug entry can be seen at [2].
>>>
>>>  From my understanding of the spec and also based on Alex's answer at
>>> [3], I think that the fact that the code compiles in 7 is a bug and thus
>>> 8 can be considered correct. For this reason I don't think that there is
>>> a compatibility issue here.
>>>
>>> I have modified the code of ReproOne.java to:
>>>
>>> --------------------------------------------------------------------------------
>>>
>>>
>>> import java.util.List;
>>>
>>> class ReproOne {
>>>
>>>    static class Baz<T> {
>>>      public static List<Baz<Object>> getElements(Baz<Object>
>>> transcoder) {
>>>        return null;
>>>      }
>>>    }
>>>
>>>    private static void bar(Baz arg) {
>>>      Baz element = Baz.getElements(arg).get(0);
>>>    }
>>> }
>>> -----------------------------------------------------------------------------------
>>>
>>>
>>>
>>> Which probably shows more clearly the fact that after erasing the return
>>> value of getElements() to "java.util.List" the type of get(0) is Object
>>> and thus not assignable to a variable of type Baz.
>>>
>>> Thanks,
>>> Vicente.
>>>
>>> [1] http://hg.openjdk.java.net/jdk8/tl/langtools/rev/48ee63caaa93
>>> [2] https://bugs.openjdk.java.net/browse/JDK-7144506
>>> [3]
>>> http://mail.openjdk.java.net/pipermail/compiler-dev/2013-October/007726.html
>>>
>>>
>>>
>>> On 17/10/13 01:48, cushon wrote:
>>>> Forwarded from compiler-dev at Alex Buckley's suggestion. Original
>>>> thread:
>>>> http://mail.openjdk.java.net/pipermail/compiler-dev/2013-October/007726.html
>>>>
>>>>
>>>>
>>>>
>>>> I found some cases where javac 8 behaviour diverges from javac 7,
>>>> and I'm
>>>> interested in knowing whether this is a bug or an intentional change.
>>>>
>>>> The following programs do not compile with the jdk8 javac. (I tried
>>>> b111 and
>>>> 954dd199d6ff). All of the programs compile with the jdk7 javac.
>>>>
>>>> -------------------------------------------------------------------------------
>>>>
>>>>
>>>> import java.util.List;
>>>>
>>>> class ReproOne {
>>>>
>>>>    static class Baz<T> {
>>>>      public static List<Baz<Object>> getElements(Baz<Object>
>>>> transcoder) {
>>>>        return null;
>>>>      }
>>>>    }
>>>>
>>>>    private static void bar(Baz arg) {
>>>>      for (Baz element : Baz.getElements(arg)) {}
>>>>    }
>>>> }
>>>> -------------------------------------------------------------------------------
>>>>
>>>>
>>>> abstract class ReproTwo<T> {
>>>>
>>>>    class Bar<E> {}
>>>>
>>>>    T get(Bar<? extends T> arg1, Bar arg2) {
>>>>      return circularGet(arg2, arg2);
>>>>    }
>>>>
>>>>    abstract T circularGet(final Bar<? extends T> arg1, final Bar<?>
>>>> arg2);
>>>> }
>>>> -------------------------------------------------------------------------------
>>>>
>>>>
>>>> abstract class ReproThree<T, V> {
>>>>
>>>>    class Binding<E> {}
>>>>    class ProviderBinding<E> extends Binding<E> {}
>>>>
>>>>    abstract V visitOther(Binding<? extends T> binding);
>>>>
>>>>    public V visitTwo(ProviderBinding<? extends T> providerBinding) {
>>>>      return visitOther((Binding) providerBinding);
>>>>    }
>>>> }
>>>> -------------------------------------------------------------------------------
>>>>
>>>>
>>>>
>>>> javac output:
>>>>
>>>> ReproOne.java:12: error: incompatible types: Object cannot be
>>>> converted to
>>>> Baz
>>>>      for (Baz element : Baz.getElements(arg)) {}
>>>>                                        ^
>>>>
>>>> ReproTwo.java:6: error: incompatible types: Object cannot be converted
>>>> to T
>>>>      return circularGet(arg2, arg2);
>>>>                        ^
>>>>    where T is a type-variable:
>>>>      T extends Object declared in class ReproTwo
>>>>
>>>> ReproThree.java:10: error: incompatible types: Object cannot be
>>>> converted
>>>> to V
>>>>      return visitOther((Binding) providerBinding);
>>>>                       ^
>>>>    where V is a type-variable:
>>>>      V extends Object declared in class ReproThree
>>>>
>>>
>


More information about the compiler-dev mailing list