Bug 209071

Summary: [1.5][compiler] Obvious type errors with generic types not caught at compile time
Product: [Eclipse Project] JDT Reporter: Eric Bodden <eric>
Component: CoreAssignee: Philipe Mulet <philippe_mulet>
Status: VERIFIED INVALID QA Contact:
Severity: normal    
Priority: P3 CC: Olivier_Thomann
Version: 3.3   
Target Milestone: 3.4 M4   
Hardware: PC   
OS: Linux   
Whiteboard:

Description Eric Bodden CLA 2007-11-07 13:48:41 EST
Build ID: I20071016-1215

Try to compile this code...

Set<List> listSet = new HashSet<List>();
Set<List> otherListSet = new HashSet<List>();
otherListSet.add((List) listSet);

Set<String> stringSet = new HashSet<String>();
Set<String> otherStringSet = new HashSet<String>();
otherStringSet.add((String) stringSet);

The first block of code compiles fine but gives a runtime error, stating that Set<String> cannot be cast to String. The second does not compile, giving the same error at compile time.

Now what I don't understand: Why, in the case of a concrete type parameter (String) is the error reported statically but not in the case of an interface type parameter?

What I even understand less: javac seems to expose the same strange behavior... How can this not be a bug?
Comment 1 Philipe Mulet CLA 2007-11-22 04:23:59 EST
The difference comes from the fact that String is a final class, so statically the compiler can tell no better subtype may show up at runtime, hence the cast is refused at compile time.

For the first case, with interface, you could imagine the runtime object to be a subtype of Set which implements List, hence the cast would be legite.
In your example, we can easily spot that HashSet doesn't implement List, hence it could statically be doomed, but the compiler is not checking based on assigned values, only using declaring types.

So, by the spec, our behavior is fine.

Added GenericTypeTest#test1221
Closing as INVALID.
Comment 2 Eric Bodden CLA 2007-11-22 10:06:32 EST
Thanks, Philippe, for the explanation. However I still have one question:

(In reply to comment #1)
> In your example, we can easily spot that HashSet doesn't implement List, hence
> it could statically be doomed, but the compiler is not checking based on
> assigned values, only using declaring types.

Even in that case the cast should be invalid. The declared type is Set<List>, which certainly is not a subtype of List. So how can this cast succeed?
Comment 3 Philipe Mulet CLA 2007-11-23 09:14:04 EST
What if later at runtime the actual value to cast is of type X, where X implements both Set<List> and List ?
Comment 4 Eric Bodden CLA 2007-11-23 09:52:56 EST
(In reply to comment #3)
> What if later at runtime the actual value to cast is of type X, where X
> implements both Set<List> and List ?
> 

Ahh, now I got it. Thanks a lot for the clarification!
Comment 5 Kent Johnson CLA 2007-12-11 11:46:56 EST
Verified for 3.4M4 using build I20071210-1800.