JDK-8032268 : compilation mismatch between javac 8 source 7 and javac 7 source 7
  • Type: Bug
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 7u45
  • Priority: P3
  • Status: Resolved
  • Resolution: Not an Issue
  • Submitted: 2014-01-20
  • Updated: 2014-06-27
  • Resolved: 2014-06-27
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 9
9Resolved
Related Reports
Relates :  
Description
The following code:

import java.util.Comparator;

class GenericMethod {
     <E extends Comparable<E>> Comparator<E> getComparator() {
         return null;
     }

     <E> void useComparator(Comparator<? super E> comparator) {
     }

     void test() {
         useComparator(this.getComparator());
     }
}

Compiles with javac8 -target 7 but fails to compile with javac7 target 7.
Comments
To clarify, the issue here is that the JLS 7 algorithm, as implemented by javac 7, produces an error, while the JLS 7 algorithm, as implemented by javac 8, does not produce an error. One of them must be wrong. (The relevant flag is -source 7, not -target 7.) Some historical background. JLS 7 added the following clause to 15.12.2.8: "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." This was viewed as a bug fix; running javac 6 on the expression 'getComparator().foo()' (forcing a type error) will reveal that inference resolves to E=Object, and then fails for not conforming to the bound on E; while running javac 7 (-source 5, -source 6, or -source 7) will reveal that the invocation successfully has type Comparator<CAP#1> (where CAP#1 extends Comparator<CAP#1>). The test invocation compiles as follows: javac 6 (-source 6): inferred Object (for getComparator) out of bounds javac 7 (-source 6 or 7): inferred Object (for useComparator) inconsistent with argument type javac 8 (-source 6 or 7): no error For comparison, this compiles for all of the above: <X extends Comparator<X>> void test(Comparator<X> arg) { useComparator(arg); } In principle, the behavior should be the same: the argument is a Comparator<SomeVariable>, and we should infer E <: SomeVariable. My conclusion is that javac 7 is in error, while javac 8 is behaving correctly. (But see also JDK-8033718, which illustrates other anomalies involving capture variables in inference.)
05-02-2014

The "target 7" is mostly irrelevant to this discussion. The report boils down to "the code does not compile with JDK 7 javac; it does compile with JDK 8 javac". The error message from JDK 7 javac is as follows: src/GenericMethod.java:13: error: invalid inferred types for E; actual argument Comparator<CAP#1> cannot be converted to Comparator<? super Object> by method invocation conversion useComparator(this.getComparator()); ^ where E is a type-variable: E extends Object declared in method <E>useComparator(Comparator<? super E>) where CAP#1 is a fresh type-variable: CAP#1 extends Comparable<CAP#1> from capture of ? 1 error Thus it seems like this reduces to JDK 8 javac is better at inference than JDK 7 javac, implying this is Not A Bug.
21-01-2014