JDK-6371674 : inference: Inferred types' bounds should help infer unconstrained type variables
  • Type: Enhancement
  • Component: specification
  • Sub-Component: language
  • Affected Version: 5.0
  • Priority: P5
  • Status: Closed
  • Resolution: Not an Issue
  • OS: linux
  • CPU: x86
  • Submitted: 2006-01-12
  • Updated: 2011-07-21
  • Resolved: 2011-07-21
Related Reports
Relates :  
Relates :  
Relates :  
Description
FULL PRODUCT VERSION :
java version "1.5.0_05"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_05-b05)
Java HotSpot(TM) Client VM (build 1.5.0_05-b05, mixed mode, sharing)


A DESCRIPTION OF THE PROBLEM :
Invalid generics code does compiles under certain conditions

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Try to compile the code given.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The code should not compile
ACTUAL -
The code compiles

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
package tests;

import java.util.Collection;
import java.util.Collections;

public class CompileTest1 {

	class Request<R extends Request<R, V>,V> {}

	class RequestMap {
		public <R extends Request<R, W>,W> R intersection (Collection<R> c) {
			// In my real code I make use of W of course
			return null;
		}
	}

	class DeltaRequest extends Request<DeltaRequest,double[]> {}

	public void test () {
		RequestMap m = new RequestMap ();
		Collection<DeltaRequest> c = Collections.singleton (new DeltaRequest ());
		// Why does this line compile?
		DeltaRequest o = m.intersection (c);
	}
}


---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Err ...

Comments
EVALUATION The code in the Description compiles, as it should. The issue is that no good type is inferred for W in the invocation of: public <R extends Request<R, W>,W> R intersection (Collection<R> c) The JLS infers R from the type of the actual argument, so resorts to inferring W=Object. javac knows how to do better: since W is determined by DeltaRequest's superclass, javac infers W=double[] by pattern-matching against that superclass. (Demonstrate by changing the return type above to W.) Amusingly, JLS 15.12.2.8 says "If any of the method's type arguments were not inferred from the types of the actual arguments..." - and javac is indeed inferring W from the type of the actual argument (indirectly, via its superclass), just via a non-JLS mechanism. 6369608 already proposes using more information to infer previously-unconstrained type variables. Extending the inference to use R's bound is hard in general, but where R's bound (Request<R,W>) matches a purely ground class (Request<DeltaRequest,double[]>), we can profitably use the info at the start of 15.12.2.8: "If a formal type argument R has been inferred as C, and R's bound includes an uninferred type variable W, then W may be inferred by unifying R's bound with C's type arguments."
07-09-2007

EVALUATION Responding to SDN comment: This is apparently a specification bug.
25-01-2006

EVALUATION I don't see the problem with this line: DeltaRequest o = m.intersection (c); c is of type Collection<DeltaRequest>. DeltaRequest is a subtype of Request<DeltaRequest,double[]> so DeltaRequest is the type inferred for R in the call to m.intersection. Since m.intersection returns R (which is DeltaRequest), the line appears to be fine.
13-01-2006