EVALUATION
A more general fix has been pushed in the 7 repository - see 6650759. As a result, the test case above now compiles w/o problems.
|
|
|
EVALUATION
The fix of this bug caused a significant amount of compatibility issues (see 6650759, 6559165, 6536404 and related CRs).
|
|
|
SUGGESTED FIX
Index: j2se/src/share/classes/com/sun/tools/javac/comp/Infer.java
--- /tmp/geta31570 2006-11-22 16:46:50.000000000 -0800
+++ /tmp/getb31570 2006-11-22 16:46:50.000000000 -0800
@@ -309,50 +309,38 @@
}
}
- // repeatedly minimize undetvars, and check against bounds
- // until all type variables are instantiated to non bottom
- // types or no further progress is made.
-
- //-System.err.println("undetvars="+undetvars);//DEBUG
- //-System.err.println("targs="+targs);//DEBUG
-
- ListBuffer<Type> restvars; // type variables instantiated to bottom
- ListBuffer<Type> insttypes; // instance types.
- int restlen = undetvars.length(); // length of restvars
- int restlen1; // length of restvars in previous iteration
-
- do {
// minimize as yet undetermined type variables
- for (List<Type> l = undetvars; l.nonEmpty(); l = l.tail) {
- minimizeInst((UndetVar) l.head, warn);
- }
+ for (Type t : undetvars)
+ minimizeInst((UndetVar) t, warn);
+
+ /** Type variables instantiated to bottom */
+ ListBuffer<Type> restvars = new ListBuffer<Type>();
+
+ /** Instantiated types or TypeVars if under-constrained */
+ ListBuffer<Type> insttypes = new ListBuffer<Type>();
+
+ /** Instantiated types or UndetVars if under-constrained */
+ ListBuffer<Type> undettypes = new ListBuffer<Type>();
- restvars = new ListBuffer<Type>();
- insttypes = new ListBuffer<Type>();
- ListBuffer<Type> insttypes1 = new ListBuffer<Type>();
- // same as insttypes, except that UndetVars replace TypeVars.
- for (List<Type> l = undetvars; l.nonEmpty(); l = l.tail) {
- UndetVar uv = (UndetVar) l.head;
+ for (Type t : undetvars) {
+ UndetVar uv = (UndetVar)t;
if (uv.inst.tag == BOT) {
restvars.append(uv.qtype);
insttypes.append(uv.qtype);
- insttypes1.append(uv);
+ undettypes.append(uv);
uv.inst = null;
} else {
insttypes.append(uv.inst);
- insttypes1.append(uv.inst);
+ undettypes.append(uv.inst);
}
}
- checkWithinBounds(tvars, insttypes1.toList(), warn);
- restlen1 = restlen;
- restlen = restvars.length();
- } while (restlen != 0 && restlen != restlen1);
+ checkWithinBounds(tvars, undettypes.toList(), warn);
- if (restlen != 0) {
+ if (!restvars.isEmpty()) {
// if there are uninstantiated variables,
// quantify result type with them
- mt = new MethodType(
- mt.argtypes, new ForAll(restvars.toList(), mt.restype),
+ mt = new MethodType(mt.argtypes,
+ new ForAll(restvars.toList(), mt.restype),
mt.thrown, syms.methodClass);
}
|
|
|
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);
}
}
###@###.### 2005-06-12 09:05:58 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());
###@###.### 2005-06-12 09:05:59 GMT
|
|
|
|