JDK-6278587 : Compiler fails to infer correct type for under-constrained type variables
  • Type: Bug
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 5.0,6
  • Priority: P3
  • Status: Closed
  • Resolution: Cannot Reproduce
  • OS: generic
  • CPU: generic
  • Submitted: 2005-06-01
  • Updated: 2017-05-16
  • Resolved: 2010-08-18
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 7 Other
7Resolved OpenJDK6Resolved
Related Reports
Duplicate :  
Duplicate :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
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

###@###.### 2005-06-01 00:42:45 GMT

Comments
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.
18-08-2010

EVALUATION The fix of this bug caused a significant amount of compatibility issues (see 6650759, 6559165, 6536404 and related CRs).
03-03-2009

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); }
23-11-2006

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
12-06-2005

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
12-06-2005