inference trouble with recursive generics and raw types

Stephan Herrmann stephan.herrmann at berlin.de
Sun Nov 3 09:27:53 PST 2013


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;
}
}

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?

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

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 :)

best,
Stephan



More information about the lambda-spec-observers mailing list