Java 9 ea154 javac compiler error - legit or bug?
Maurizio Cimadamore
maurizio.cimadamore at oracle.com
Thu Feb 9 13:31:04 UTC 2017
Hi Vitaly,
the situation is a tad convoluted; basically there's a long-standing
javac discrepancy which allowed javac to erase the return type of an
unchecked call *after* some type inference has been performed. This
behavior is well described here:
https://bugs.openjdk.java.net/browse/JDK-8135087
In your example, that means that, since the first actual argument to
'foo' has type Class<String> and the first formal is Class<T>, javac is
able to infer that T = String - which gives you a fully instantiated
'foo' with signature:
String foo(Class<String> c, Collection<? super String> baz)
Then, as an unchecked conversion has been required for this method call
(for the second argument), javac proceeds to erase the signature - but
there's nothing to do! That is, erasure(String) = String, so the
invocation type of the inner most call has a return type 'String'.
That's different from what the spec says - as the spec wants to erase
the *declared signature* of the method if an unchecked conversion occurs
- in which case the invocation return type would be just Object (and a
compiler error would be issued). This discrepancy will be addressed as
part of JDK 10.
That said, JDK-8078093 accidentally introduced a change in this area -
in method context the current javac implementation would erase the
declared signature; while this behavior is compatible with what the spec
say, as you observed, it's completely inconsistent with what javac does
in assignment context, and it's also inconsistent with almost everything
else javac does (hence the weird error you get 'expected: String -
found: String'). This is just a plain bug - the fix for 8078093 was
never meant to alter behavior of type-checking with unchecked calls and
generic methods.
In the short term we plan to restore the original behavior (as with JDK
8). In the medium term we plan to get rid of this discrepancy for good.
So, should the program compile? If you follow the spec literally, no, it
shouldn't. But the aim is to keep stuff like this working, until we come
up with a more general cleanup in this area.
I hope this clarifies the issue.
Meanwhile, I filed this bug:
https://bugs.openjdk.java.net/browse/JDK-8174249
to keep track of this issue.
Maurizio
On 09/02/17 04:09, Vitaly Davidovich wrote:
> Hi Maurizio,
>
> Thanks for the reply. So you're saying the example using assignment
> context shouldn't compile either? Also, the call to 'foo' is unchecked
> in the wildcard argument, but it has a concrete type in the first
> argument. Are you saying that any unchecked param results in return
> type erasure?
>
> Thanks
>
> On Wed, Feb 8, 2017 at 8:38 PM Maurizio Cimadamore
> <maurizio.cimadamore at oracle.com
> <mailto:maurizio.cimadamore at oracle.com>> wrote:
>
> Hi,
> it seems like the behavior you observed started in b83 - as a
> result of this:
>
> https://bugs.openjdk.java.net/browse/JDK-8078093
>
> I believe the error is correct (although the diagnostic has always
> been broken since b83 in the 'verbose' mode - the non-verbose mode
> - w/o -Xdiags:verbose is fine). That is, the call to 'foo' is
> unchecked, so the return type should be erased. There seems to be
> an inconsistency in how javac handles this in method context
> compared to assignment context, and that needs to be looked at.
>
> Thanks
>
>
> Maurizio
>
>
>
> On 08/02/17 19:23, Vitaly Davidovich wrote:
>> Hi all,
>>
>> Given the following code:
>>
>> import java.util.ArrayList;
>> import java.util.Collection;
>>
>> public class Foo {
>> static <T> T foo(Class<T> c, Collection<? super T> baz) {
>> return null;
>> }
>>
>> static void bar(String c) {
>>
>> }
>>
>> @SuppressWarnings("unchecked")
>> public static void main(String[] args) {
>> // this works
>> bar(foo(String.class, new ArrayList<String>()));
>>
>> // this works with a warning
>> String s = foo(String.class, new ArrayList());
>> bar(s);
>>
>> // this causes an error on JDK9
>> bar(foo(String.class, new ArrayList()));
>> }
>> }
>>
>> javac 9-ea (build 9-ea+154) fails with this interesting error (on
>> the last line in main, as the comments there indicate):
>>
>> Foo.java:23: error: method bar in class Foo cannot be applied to
>> given types;
>> bar(foo(String.class, new ArrayList()));
>> ^
>> required: String
>> found: String
>> reason: argument mismatch; Object cannot be converted to String
>> 1 error
>>
>> Java 8 compiles fine, and the other 2 lines compile in the same
>> java 9 build as well.
>>
>> Is this a javac bug or legit? It seems like a compiler error. At
>> a minimum, the diagnostic output "required String, found String"
>> is confusing.
>>
>> Thanks
>>
>>
>
> --
> Sent from my phone
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.openjdk.java.net/pipermail/compiler-dev/attachments/20170209/f319ae44/attachment.html>
More information about the compiler-dev
mailing list