Java 9 ea154 javac compiler error - legit or bug?

classic Classic list List threaded Threaded
9 messages Options
Reply | Threaded
Open this post in threaded view
|

Java 9 ea154 javac compiler error - legit or bug?

Vitaly Davidovich
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


Reply | Threaded
Open this post in threaded view
|

Re: Java 9 ea154 javac compiler error - legit or bug?

Maurizio Cimadamore

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



Reply | Threaded
Open this post in threaded view
|

Re: Java 9 ea154 javac compiler error - legit or bug?

Vitaly Davidovich
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 <[hidden email]> 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
Reply | Threaded
Open this post in threaded view
|

Re: Java 9 ea154 javac compiler error - legit or bug?

Maurizio Cimadamore

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 <[hidden email]> 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

Reply | Threaded
Open this post in threaded view
|

Re: Java 9 ea154 javac compiler error - legit or bug?

Vitaly Davidovich
Hi Maurizio,

Thanks for the elaboration - much appreciated.

Which EA build do you think will have a fix for this issue?

On Thu, Feb 9, 2017 at 8:31 AM Maurizio Cimadamore <[hidden email]> wrote:

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 <[hidden email]> 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

--
Sent from my phone
Reply | Threaded
Open this post in threaded view
|

Re: Java 9 ea154 javac compiler error - legit or bug?

Maurizio Cimadamore

On 09/02/17 16:39, Vitaly Davidovich wrote:
Hi Maurizio,

Thanks for the elaboration - much appreciated.

Which EA build do you think will have a fix for this issue?
I've just pushed this today, so - finger crossed - it should make the next one (157)

Maurizio

On Thu, Feb 9, 2017 at 8:31 AM Maurizio Cimadamore <[hidden email]> wrote:

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 <[hidden email]> 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

--
Sent from my phone

Reply | Threaded
Open this post in threaded view
|

Re: Java 9 ea154 javac compiler error - legit or bug?

Vitaly Davidovich
Awesome - thanks!

On Thu, Feb 9, 2017 at 5:03 PM Maurizio Cimadamore <[hidden email]> wrote:

On 09/02/17 16:39, Vitaly Davidovich wrote:
Hi Maurizio,

Thanks for the elaboration - much appreciated.

Which EA build do you think will have a fix for this issue?
I've just pushed this today, so - finger crossed - it should make the next one (157)


Maurizio


On Thu, Feb 9, 2017 at 8:31 AM Maurizio Cimadamore <[hidden email]> wrote:

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 <[hidden email]> 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

--
Sent from my phone

--
Sent from my phone
Reply | Threaded
Open this post in threaded view
|

Re: Java 9 ea154 javac compiler error - legit or bug?

Vitaly Davidovich
Hi Maurizio,

Just wanted to follow up and confirm that 157 fixes the issue - thanks again for the lightning turnaround!

On Thu, Feb 9, 2017 at 5:04 PM Vitaly Davidovich <[hidden email]> wrote:
Awesome - thanks!

On Thu, Feb 9, 2017 at 5:03 PM Maurizio Cimadamore <[hidden email]> wrote:

On 09/02/17 16:39, Vitaly Davidovich wrote:
Hi Maurizio,

Thanks for the elaboration - much appreciated.

Which EA build do you think will have a fix for this issue?
I've just pushed this today, so - finger crossed - it should make the next one (157)


Maurizio


On Thu, Feb 9, 2017 at 8:31 AM Maurizio Cimadamore <[hidden email]> wrote:

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 <[hidden email]> 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

--
Sent from my phone

--
Sent from my phone
--
Sent from my phone
Reply | Threaded
Open this post in threaded view
|

Re: Java 9 ea154 javac compiler error - legit or bug?

Maurizio Cimadamore

Phew - thanks!

Maurizio


On 23/02/17 22:05, Vitaly Davidovich wrote:
Hi Maurizio,

Just wanted to follow up and confirm that 157 fixes the issue - thanks again for the lightning turnaround!

On Thu, Feb 9, 2017 at 5:04 PM Vitaly Davidovich <[hidden email]> wrote:
Awesome - thanks!

On Thu, Feb 9, 2017 at 5:03 PM Maurizio Cimadamore <[hidden email]> wrote:

On 09/02/17 16:39, Vitaly Davidovich wrote:
Hi Maurizio,

Thanks for the elaboration - much appreciated.

Which EA build do you think will have a fix for this issue?
I've just pushed this today, so - finger crossed - it should make the next one (157)


Maurizio


On Thu, Feb 9, 2017 at 8:31 AM Maurizio Cimadamore <[hidden email]> wrote:

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 <[hidden email]> 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

--
Sent from my phone

--
Sent from my phone
--
Sent from my phone