|
Quick Lists
|
|
Bug ID:
|
6278587
|
|
Votes
|
2
|
|
Synopsis
|
Compiler fails to infer correct type for under-constrained type variables
|
|
Category
|
java:compiler
|
|
Reported Against
|
|
|
Release Fixed
|
7(b05)
|
|
State
|
9-Fix Failed,
bug
|
|
Priority:
|
3-Medium
|
|
Related Bugs
|
6284158
,
6468384
,
6491939
,
6498829
,
6536404
,
6559165
,
6570321
,
6650759
|
|
Submit Date
|
01-JUN-2005
|
|
Description
|
This program doesn't compile
import java.util.*;
public class TestGenerics {
/**Subclasses are parameterized by their own type*/
private static abstract class SelfType<T extends SelfType<T>>{
public abstract T getThis();
}
/**Supertype inherits directly from the parameterized SelfType*/
private static class SuperType extends SelfType<SuperType>{
@Override
public SuperType getThis(){
return this;
}
}
/**Subtype inherits indirectly from the parameterized SelfType*/
private static class SubType extends SuperType{}
/**Creates a list containing a single SelfType*/
public static <T extends SelfType<T>> List<T> makeSingletonList(T t){
return Collections.singletonList(t);
}
/**
* Creates a list containing a single SelfType, allowing the list's
* element-type to be a supertype of the type of its single element
*/
public static <T extends SelfType<T>,S extends T> List<T> makeSingletonList2(S s){
return Collections.singletonList((T)s);
}
public static void main(String[] args){
/*making lists of super types works fine ...*/
makeSingletonList(new SuperType());
List<SuperType> lsup = makeSingletonList(new SuperType());
/*but we can't make a list of sub types; seems weird ...*/
List<SubType> lsub = makeSingletonList(new SubType()); //ERROR
/*can't even call it w/o assigning the return value:*/
makeSingletonList(new SubType()); //ERROR
/*so instead, we should be able to make lists of super type containing sub type elements*/
makeSingletonList2(new SubType()); //ERROR
/*even if we assign the return value:*/
lsup = makeSingletonList2(new SubType()); // ERROR (eclipse is okay with this though)
/*this still doesn't work either:*/
lsub = makeSingletonList2(new SubType()); // ERROR
/*we can make lists of super type this way though*/
makeSingletonList2(new SuperType()); // (eclipse doesn't like this though)
/*also ok if we assign the return value*/
lsup = makeSingletonList2(new SuperType());
}
}
See http://forum.java.sun.com/thread.jspa?threadID=632009&tstart=0
xxxxx@xxxxx 2005-06-01 00:42:45 GMT
|
|
Work Around
|
Work around for the reduced case:
D<B> d = this.<B,C>m(c);
Work around for the original example:
makeSingletonList(new SuperType());
List<SuperType> lsup = makeSingletonList(new SuperType());
// This can't be made to work, List<SuperType> is not
// a subtype of List<SubType>
List<SubType> lsub = TestGenerics.<SuperType>makeSingletonList(new SubType());
TestGenerics.<SuperType>makeSingletonList(new SubType());
TestGenerics.<SuperType,SubType>makeSingletonList2(new SubType());
lsup = TestGenerics.<SuperType,SubType>makeSingletonList2(new SubType());
// Can't work, see above
lsub = TestGenerics.<SuperType,SubType>makeSingletonList2(new SubType());
xxxxx@xxxxx 2005-06-12 09:05:59 GMT
|
|
Evaluation
|
Let's examine each "error":
List<SubType> lsub = makeSingletonList(new SubType());
According to JLS 3rd Ed. (15.12.2.2 Phase 1: Identify
Matching Arity Methods Applicable by Subtyping) inference
is started with the initial constraint SubType << T.
This infers the type SubType for T. In JLS lingo, this
gives U1 = SubType and S1 = SubType. In order for the
method to be applicable, A1 must be a subtype of
S1 which is trivially true (SubType is a subtype of itself).
However, the inferred type U1 must also be a subtype
of B1[R1=U1, ...] which translates to:
SubType must be a subtype of SelfType<SubType> which
it isn't.
The same analysis holds for
makeSingletonList(new SubType());
Next is
makeSingletonList2(new SubType());
Here the inference is simpler, the type inferred
for S is SubType, but T is under constrained, so
Object is inferred for T. However, Object is not
a subtype of SelfType<Object> why the method
invocation fails.
Next is
lsup = makeSingletonList2(new SubType());
Here again, T is under constrained but there is an
expected type, so the type inferred for T should
be SuperType which is indeed a subtype of SelfType<SuperType>.
This is a bug.
Lastly, consider
lsub = makeSingletonList2(new SubType());
Again, T is under constrained so the expected type
is considered and SubType is inferred for T. However,
SubType is not a subtype of SelfType<SubType>.
In summary, there is one bug here and it can be reduced to this:
abstract class Simple {
interface A<T extends A<T>> {}
interface B extends A<B> {}
interface C extends B {}
interface D<T> {}
abstract <T extends A<T>, S extends T> D<T> m(S s);
{
C c = null;
D<B> d = m(c);
}
}
xxxxx@xxxxx 2005-06-12 09:05:58 GMT
The fix of this bug caused a significant amount of compatibility issues (see 6650759, 6559165, 6536404 and related CRs).
Posted Date : 2009-03-03 17:36:42.0
|
|
Comments
|
Submitted On 10-JUN-2005
mmchenry@carnegielearning.com
This bug also submitted to the eclipse project:
https://bugs.eclipse.org/bugs/show_bug.cgi?id=98538
PLEASE NOTE: JDK6 is formerly known as Project Mustang
|
|
|
 |