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

Bug 492781

Summary: [Generics] Type mismatch, field's generic type lost when generic type is omitted for the field's class
Product: [Eclipse Project] JDT Reporter: Nathan Sweet <misc>
Component: CoreAssignee: Sasikanth Bharadwaj <sasikanth.bharadwaj>
Status: CLOSED INVALID QA Contact:
Severity: normal    
Priority: P3 CC: jarthana, stephan.herrmann
Version: 4.5.1   
Target Milestone: 4.6 RC1   
Hardware: PC   
OS: Windows 10   
Whiteboard:

Description Nathan Sweet CLA 2016-05-01 18:57:37 EDT
This code fails to compile on the line indicated:

public class Test {
static public class A<Z> {
	B<String> array;
}
static public class B<Y> {
	public Y get () {
		return null;
	}
}
static public void main (String[] args) throws Exception {
	A a = new A();
	String x = a.array.get(); // Type mismatch: cannot convert from Object to String
}
}

Compilation succeeds if local "a" is declared with any generic type, such as "A<?> a", "A<Object> a", "A<Integer> a", etc.

Expected: the generic type of A not to affect the "B<String> array" field.
Comment 1 Jay Arthanareeswaran CLA 2016-05-02 03:11:15 EDT
I believe this is the expected behavior. Javac reports the same error.

Sasi, please take this to completion.
Comment 2 Nathan Sweet CLA 2016-05-02 11:36:16 EDT
My apoligies, I seem to have found why it occurs in the spec:
https://docs.oracle.com/javase/specs/jls/se8/html/jls-4.html#jls-4.8
"The type of a constructor (§8.8), instance method (§8.4, §9.4), or non-static field (§8.3) of a raw type C that is not inherited from its superclasses or superinterfaces is the raw type that corresponds to the erasure of its type in the generic declaration corresponding to C."

I still don't understand why fields of a raw type would also become raw types when their generic types are unrelated to the generic types of the declaring class, but it seems there is no bug here.
Comment 3 Stephan Herrmann CLA 2016-05-02 16:16:59 EDT
(In reply to Nathan Sweet from comment #2)
> My apoligies, I seem to have found why it occurs in the spec:
> https://docs.oracle.com/javase/specs/jls/se8/html/jls-4.html#jls-4.8
> "The type of a constructor (§8.8), instance method (§8.4, §9.4), or
> non-static field (§8.3) of a raw type C that is not inherited from its
> superclasses or superinterfaces is the raw type that corresponds to the
> erasure of its type in the generic declaration corresponding to C."

Thanks for digging out the JLS reference.
I agree that this explains why the error reported from both compilers is indeed mandated by JLS.
 
> I still don't understand why fields of a raw type would also become raw
> types when their generic types are unrelated to the generic types of the
> declaring class, but it seems there is no bug here.

"Why"-questions regarding JLS are difficult to answer, but I think it has to do with the intention behind introducing raw types in the first place: to allow interfacing new code with pre-java-5 legacy code. It wouldn't be consistent to trust *any* generic type information across this bridge.

This also hints at the solution: never use raw types. Never. We're speaking about a "feature" that has been deprecated more than 10 years ago.
Comment 4 Nathan Sweet CLA 2016-05-02 16:55:38 EDT
(In reply to Stephan Herrmann from comment #3)
> "Why"-questions regarding JLS are difficult to answer, but I think it has to
> do with the intention behind introducing raw types in the first place: to
> allow interfacing new code with pre-java-5 legacy code. It wouldn't be
> consistent to trust *any* generic type information across this bridge.
> 
> This also hints at the solution: never use raw types. Never. We're speaking
> about a "feature" that has been deprecated more than 10 years ago.

Very interesting, thanks for the explanation. I tend to use raw types when I mean <?>, simply for brevity. It's nice to know the differences.