inference trouble with recursive generics and raw types

Dan Smith daniel.smith at
Mon Nov 4 08:38:55 PST 2013

On Nov 3, 2013, at 10:27 AM, Stephan Herrmann <stephan.herrmann at> wrote:

> Working on the latest spec I'm seeing a discrepancy between
> the spec and actual javac behavior.
> interface Foo<T extends Foo<T>> {
> }
> class Bar<Q> {
> }
> public class X {
> void readDatabase() {
> Bar<Foo> bar = new Bar<Foo>();
> read(bar, "sadasd"); // infer this call!
> }
> <P extends Foo<P>, D extends Bar<P>>
> D read(D d, String s) {
> return d;
> }
> }

This is essentially the same issue that you reported on October 10, right?

public class X {
 public static void main(String[] args) {
   EntityKey entityKey = null;
   new EntityCondenser().condense(entityKey);
 public static class EntityCondenser {
   <I, E extends EntityType<I, E, K>, K extends EntityKey<I>> void condense(K entityKey) {
 public class EntityKey<I> {}
 public interface EntityType<
   E extends EntityType<I, E, K>,
   K extends EntityKey<I>> {

> I see type inferencing regarding the invocation of read(..)
> producing the following:
> (a) declaration of type variable P produces this dependency:
> P#0 <: Foo<P#0>
> (where P#0 is an inference variable representing P)
> (b) declaration of type variable D produces this type bound:
> D#1 <: Bar<P#0>
> (c) the constraint formula for the argument expression 'bar' yields:
> D#1 :> Bar<Foo>
> (d) incorporation of (b) and (c) yields this constraint:
> ⟨Bar<Foo> <: Bar<P#0>⟩
> (e) reduction on (d) yields this type bound:
> P#0 :> Foo
> (f) incorporating (a) with (e) yields this type constraint:
> ⟨Foo <: Foo<P#0>⟩
> At this point inference fails because the raw type Foo is not
> recognized as a legal subtype of Foo<P#0>: In 18.2.3 the
> 5.2nd bullet applies: We need to find the parameterization
> of Foo that is a supertype of Foo, which, however, cannot be
> determined since Foo (substitute for S) is a raw type.
> Is there a mistake in my derivation?

Nope, I agree with your explanation (except step (e) should be an eq bound, not a lower bound).  Crucially, raw Foo is not within the upper bound of P#0.

> OTOH, all compilers that I tested accept the above program
> (from javac 1.5 to 8b112 as well as ecj).

Yes, I identified this as a bug in your last report.

Significantly, an invocation of the form 'this.<Foo,Bar<Foo>>read(bar, "sadasd")' will compile.  So this isn't really specifically an inference issue: the compilers simply believe that a raw type is "within" a bound that is a parameterization of that type.  And that interpretation is flat-out wrong.  Bounds are subtyping assertions.  JLS is consistent about this -- see 4.5 and

Here's my javac bug report:

> In spite of all talk about reducing the support for raw types, the
> above example seems to be a relevant pattern, were avoidance of
> raw types is not as easy as just filling in some type parameters
> (or is the above program actually unsafe and thus can only be
> written using raw types?)
> Unless I'm missing s.t.:
> Either the spec needs to be extended to gracefully handle raw
> types in at least this particular rule.
> Or all compilers have a bug and must be fixed :)

The compilers have a bug.

It might make sense to reexamine the spec here if there were some sort of lack of clarity, but there's really not.  And making a change in the interpretation of bounds would be a big deal, because the use of subtyping here is fundamental to a lot of things (like inference, type variable subtyping, etc.) that are built on top.


More information about the lambda-spec-experts mailing list