JDK-7015430 : Incorrect thrown type determined for unchecked invocations
  • Type: Bug
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 7
  • Priority: P4
  • Status: Closed
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2011-01-27
  • Updated: 2011-04-20
  • Resolved: 2011-04-20
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 7
7 b134Fixed
Related Reports
Relates :  
Relates :  
Description
As demonstrated by the below test, the following from JLS 15.12.2.6 is not correctly implemented.

"If unchecked conversion was necessary for the method to be applicable then the throws clause is composed of the erasure (4.6) of the types in the method���s declared throws clause."

javac instead applies any provided type arguments to methods and constructors (as if this clause were not present), or, where type arguments are inferred, chooses an unerased thrown type variable.  Fortunately, in this latter case, I don't think there's any way to distinguish type "E" from type "erasure of E", so that case only has an impact on error messages (unless I'm wrong).

The correct behavior for constructor invocations is unclear -- I've suggested below what seems the most reasonable and consistent.  See also specification bug 7015422.

In my 6u22 compiler, the explicit type argument case behaved the same as the inferred type argument case, so that has since been "fixed," but the fix is not consistent with the JLS.

/**
 * Testing the following from JLS 15.12.2.6:
 * If unchecked conversion was necessary for the method to be applicable
 * then the throws clause is composed of the erasure (4.6) of the types
 * in the method���s declared throws clause.
 */
public class UncheckedInvocation {

  static <E extends Exception> Iterable<E> empty(Iterable<E> arg) throws E {
    for (E e : arg) throw e;
    return arg;
  }

  <E extends Exception> UncheckedInvocation(Iterable<E> arg) throws E {
    empty(arg);
  }

  /**
   * Method invocation, no unchecked
   * Specified thrown: RuntimeException
   * javac: RuntimeException
   * Eclipse: RuntimeException
   */
  void m1() {
    Iterable<RuntimeException> i = java.util.Collections.emptyList();
    empty(i);
  }

  /**
   * Method invocation, unchecked, inferred arguments
   * Specified thrown: Exception
   * javac: E (!)
   * Eclipse: Exception
   */
  void m2() {
    Iterable i = java.util.Collections.EMPTY_LIST;
    empty(i);
  }

  /**
   * Method invocation, unchecked, explicit arguments
   * Specified thrown: Exception
   * javac: RuntimeException
   * Eclipse: RuntimeException
   */
  void m3() {
    Iterable i = java.util.Collections.EMPTY_LIST;
    UncheckedInvocation.<RuntimeException>empty(i);
  }

  /**
   * Constructor invocation, no unchecked
   * Specified thrown: RuntimeException (unclear)
   * javac: RuntimeException
   * Eclipse: RuntimeException
   */
  void m4() {
    Iterable<RuntimeException> i = java.util.Collections.emptyList();
    new UncheckedInvocation(i);
  }

  /**
   * Constructor invocation, unchecked, inferred arguments
   * Specified thrown: Exception? (unclear)
   * javac: E (!)
   * Eclipse: Exception
   */
  void m5() {
    Iterable i = java.util.Collections.EMPTY_LIST;
    new UncheckedInvocation(i);
  }

  /**
   * Constructor invocation, unchecked, explicit arguments
   * Specified thrown: Exception? (unclear)
   * javac: RuntimeException
   * Eclipse: RuntimeException
   */
  void m6() {
    Iterable i = java.util.Collections.EMPTY_LIST;
    new <RuntimeException>UncheckedInvocation(i);
  }

}

Comments
SUGGESTED FIX A webrev of this fix is available at the following URL: http://hg.openjdk.java.net/jdk7/tl/langtools/rev/9286a5d1fae3
28-02-2011

EVALUATION We could fix the cases in which javac ends up inferring E (type-variable) for thrown types - as this is due to a simple missing erasure in Attr.java:2804. As for the general problem (javac vs. JLS 15.12.2.6) see related bug 6791481 (as it is not clear as to whether it should be regarded as a spec bug/javac bug).
15-02-2011