JDK-8078249 : Inference regression with JDK 8 and -source 7
  • Type: Bug
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 8
  • Priority: P5
  • Status: Resolved
  • Resolution: Duplicate
  • Submitted: 2015-04-21
  • Updated: 2015-12-10
  • Resolved: 2015-12-10
Related Reports
Duplicate :  
Description
This program doesn't compile when source is set to a value other than 8 (the example is a bit more verbose than necessary, to get better output):

interface Bar<X extends Bar<X>> { }

class Test {
    <A extends Bar<A>> void test() {
        A result = m();
    }

	<B extends Bar<B>> B m() {
        return null;
    }
}

Error:

/opt/JDK/8/re/b40/bin/javac -source 7 Main.java 
Main.java:7: error: incompatible types: inferred type does not conform to upper bound(s)
        A result = m();
                    ^
    inferred: B
    upper bound(s): Bar<B>,A
  where B,A are type-variables:
    B extends A
    A extends Bar<A> declared in method <A>test()
1 error

Compiling w/o the -source flag, or with a JDK 7 compiler works w/o issues.
Comments
The behavior according to JLS SE 7 is as follows: 15.12.2.8. Inferring Unresolved Type Arguments: "If Ti appears as a type argument in any Uk, then Ti is inferred to be a type variable X whose upper bound is the parameterized type given by glb(U1[Ti=X], ..., Uk[Ti=X]) and whose lower bound is the null type." Here, we have that the B inference variable has two upper bounds: B <: A (from the return type constraint) B <: Bar<B> (from the declared bound) So, the above paragraph applies, given that B has an upper bound that mentions B itself! The above paragraph mandates that the result of inference is another type-variable, let's call it B#2, whose upper bound is glb([B=B#2]A, [B=B#2]Bar<B>) = glb(A, Bar<B#2>) The glb of A and Bar<B#2> should be (handwaving a bit as this area is underspecified) the intersection type A & Bar<B#2> (since Bar is an interface). Turns out that the result of glb is not important for this case: even with this type, we have that the bound well-formedness fails as the inferred type is not a subtype of the upper bounds we started with: 1) A & Bar<B#2> <: A ? Yes, trivially. 2) A & Bar<B#2> <: [B:=A & Bar<B#2>]Bar<B> ? A & Bar<B#2> <: Bar<A & Bar<B#2>> Bar<B#2> <: Bar<A & Bar<B#2>> No [invariant parameterized types with different type arguments]. So, while javac exhibits a minor problem when computing the glb (the error message seems to sugest that javac is picking A to be the glb), the result is the same - the program should not compile as per JLS SE 7 spec. As an historical note, I recall that the javac implementation of 15.12.2.8 had a bug, as it computed glb using partially instantiated types featuring inference variables; this allowed javac to compute glb(A, Bar<B>) and get A as an answer. In other words, the fallback logic with the synthetic type variable was only applied when inference variables were seen escaping the inference context (which was not the case here). However that behavior was completely unspecified and bug prone.
21-04-2015