Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.

Bug 463825

Summary: Eclipse allows implicit conversion from T<U> to T<? extends U<?>> in method invocation context
Product: [Eclipse Project] JDT Reporter: Benjamin Horstman <bhorstman>
Component: CoreAssignee: JDT-Core-Inbox <jdt-core-inbox>
Status: CLOSED WONTFIX QA Contact: Stephan Herrmann <stephan.herrmann>
Severity: minor    
Priority: P3 CC: hudsonr, jarthana, markus.kell.r, sasikanth.bharadwaj, sebastian.zarnekow, stephan.herrmann
Version: 4.4.2   
Target Milestone: ---   
Hardware: PC   
OS: All   
Whiteboard: stalebug
Attachments:
Description Flags
I expect that eclipse should report an error in both functions none

Description Benjamin Horstman CLA 2015-04-02 11:30:08 EDT
Created attachment 252143 [details]
I expect that eclipse should report an error in both functions

Conversion from T<U> to T<U<?>> is disallowed.  However, when an intermediate function (such as guava's Lists.newArrayList) is used, eclipse allows it.  Javac 6,8,9 reports an error in both cases.  See attached example.

Output from javac:
bhorstman@bhorstman-Precision-WorkStation-T3500:~$ ~/jdk/jdk1.6.0_45/bin/javac ~/Test2.java 
^[[A/home/bhorstman/Test2.java:7: incompatible types
found   : java.util.ArrayList<Test2.GenericClass>
required: java.util.List<Test2.GenericClass<?>>
	return newArrayList(set);
	                   ^
/home/bhorstman/Test2.java:11: incompatible types
found   : java.lang.Iterable<Test2.GenericClass>
required: java.util.List<Test2.GenericClass<?>>
	List<GenericClass<?>> rv = set;	//compile error in both
	                           ^
2 errors
bhorstman@bhorstman-Precision-WorkStation-T3500:~$ ~/jdk/jdk1.8.0_20/bin/javac -Xdiags:verbose ~/Test2.java 
^[[A/home/bhorstman/Test2.java:7: error: incompatible types: cannot infer type-variable(s) E
	return newArrayList(set);
	                   ^
    (argument mismatch; Iterable<GenericClass> cannot be converted to Iterable<? extends GenericClass<?>>)
  where E is a type-variable:
    E extends Object declared in method <E>newArrayList(Iterable<? extends E>)
/home/bhorstman/Test2.java:11: error: incompatible types: Iterable<GenericClass> cannot be converted to List<GenericClass<?>>
	List<GenericClass<?>> rv = set;	//compile error in both
	                           ^
2 errors
bhorstman@bhorstman-Precision-WorkStation-T3500:~$ ~/jdk/jdk1.9.0/bin/javac -Xdiags:verbose ~/Test2.java 
/home/bhorstman/Test2.java:7: error: incompatible types: cannot infer type-variable(s) E
	return newArrayList(set);
	                   ^
    (argument mismatch; Iterable<GenericClass> cannot be converted to Iterable<? extends GenericClass<?>>)
  where E is a type-variable:
    E extends Object declared in method <E>newArrayList(Iterable<? extends E>)
/home/bhorstman/Test2.java:11: error: incompatible types: Iterable<GenericClass> cannot be converted to List<GenericClass<?>>
	List<GenericClass<?>> rv = set;	//compile error in both
	                           ^
2 errors
Comment 1 Stephan Herrmann CLA 2015-04-02 12:57:30 EDT
Get rid of your raw types (by adding wildcards) and you'll see that javac, too, accepts the variant using the helper method :)

<rant>
I personally give no priority anymore to adjusting ecj to javac wrt handling of raw types. We've already added more than enough bug-compatibility tweaks in this area. Maybe it's even one of those tweaks that in this particular situation makes ecj answer wrongly. I don't know. But I know that mimicking buggy javac wrt raw types is a battle we can never win. OTOH, raw types were deprecated right when they were introduced in Java 5, 10 years ago.
</rant>

I might reconsider if s.o. provides clear JLS-based reasoning, why the error should be reported.
Comment 2 Benjamin Horstman CLA 2015-04-02 15:52:58 EDT
Yes, the best solution is not to use raw types.  The guilty parties have been alerted :)  It's already fixed for us, I'm just reporting the (very few!) hiccups upgrading to Java 8.  

I only reported here because it seemed like eclipse was inconsistent with itself between the two cases.  I am not a JLS expert, but I was also not able to determine the correct behavior using the spec.  If you think it's not worth fixing, it's fine with me.
Comment 3 Markus Keller CLA 2015-05-27 13:25:38 EDT
Here's a related case where casting conversion fails with javac (6,7,8) but succeeds with ECJ:

import java.util.ArrayList;
import java.util.Collection;

public class Test {
public Object foo() {
	Class<ArrayList> cl = ArrayList.class; // type contains raw type
//	return (Class<?>) cl; // OK
//	return (Class<? extends ArrayList>) cl; // OK
//	return (Class<? extends Collection<?>>) cl; // javac doesn't compile
	return (Class<? extends ArrayList<?>>) cl; // javac doesn't compile
}
}

javac full version "1.8.0_60-ea-b12"
C:\...\zz1.7\src\Test.java:10: error: incompatible types: Class<ArrayList> cannot be converted to Class<? extends ArrayList<?>>
	return (Class<? extends ArrayList<?>>) cl; // javac doesn't compile
	                                       ^
1 error
Comment 4 Stephan Herrmann CLA 2015-05-28 10:42:08 EDT
(In reply to Markus Keller from comment #3)
> 	Class<ArrayList> cl = ArrayList.class; // type contains raw type

reminds me of the question: what to recommend to users in order to avoid raw types also in situations like this?

From the example I get the impression, javac won't even let you create a "Class<? extends ArrayList<?>>" value from a class literal? Bad ...

Still, we should come to our own conclusion whether or not these examples are legal.
Comment 5 Markus Keller CLA 2015-05-28 13:41:44 EDT
Yeah, as you've probably read between the lines in comment 3, I didn't come to a conclusion whether this should be allowed or not.

OTOH, I'm certain that JLS8 is still fundamentally inconsistent about raw types:
- 4.8 says: "The use of raw types is allowed only as a concession to compatibility of legacy code."
- 15.8.2 says: "The type of C.class, where C is the name of a class, interface, or array type (§4.3), is Class<C>."
=> The only conclusion would be that the class literal "ArrayList.class" is not allowed in non-legacy code. But that doesn't make much sense.

JDK bugs (with conclusions: "don't know what to do"):
https://bugs.openjdk.java.net/browse/JDK-6184881
https://bugs.openjdk.java.net/browse/JDK-6209029
Comment 6 Stephan Herrmann CLA 2015-05-28 15:03:01 EDT
(In reply to Markus Keller from comment #5)
> OTOH, I'm certain that JLS8 is still fundamentally inconsistent about raw
> types:
> - 4.8 says: "The use of raw types is allowed only as a concession to
> compatibility of legacy code."
> - 15.8.2 says: "The type of C.class, where C is the name of a class,
> interface, or array type (§4.3), is Class<C>."
> => The only conclusion would be that the class literal "ArrayList.class" is
> not allowed in non-legacy code. But that doesn't make much sense.

I fully agree.

> JDK bugs (with conclusions: "don't know what to do"):
> https://bugs.openjdk.java.net/browse/JDK-6184881
> https://bugs.openjdk.java.net/browse/JDK-6209029

thanks for digging these out. 11 years and no action, *but* a recent supportive comment ... should we hope?
Comment 7 Eclipse Genie CLA 2020-04-19 01:04:50 EDT
This bug hasn't had any activity in quite some time. Maybe the problem got resolved, was a duplicate of something else, or became less pressing for some reason - or maybe it's still relevant but just hasn't been looked at yet. As such, we're closing this bug.

If you have further information on the current state of the bug, please add it and reopen this bug. The information can be, for example, that the problem still occurs, that you still want the feature, that more information is needed, or that the bug is (for whatever reason) no longer relevant.

--
The automated Eclipse Genie.
Comment 8 Stephan Herrmann CLA 2020-04-19 05:42:05 EDT
(In reply to Stephan Herrmann from comment #6)
> (In reply to Markus Keller from comment #5)
> > OTOH, I'm certain that JLS8 is still fundamentally inconsistent about raw
> > types:
> > - 4.8 says: "The use of raw types is allowed only as a concession to
> > compatibility of legacy code."
> > - 15.8.2 says: "The type of C.class, where C is the name of a class,
> > interface, or array type (§4.3), is Class<C>."
> > => The only conclusion would be that the class literal "ArrayList.class" is
> > not allowed in non-legacy code. But that doesn't make much sense.
> 
> I fully agree.
> 
> > JDK bugs (with conclusions: "don't know what to do"):
> > https://bugs.openjdk.java.net/browse/JDK-6184881
> > https://bugs.openjdk.java.net/browse/JDK-6209029
> 
> thanks for digging these out. 11 years and no action, *but* a recent
> supportive comment ... should we hope?

Nope, those JDK bugs are dead. Hence genie's decision to close our bugs was a good one.