JDK-8135087 : Erasure for unchecked invocation happens after inference
  • Type: Bug
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 6u65,7u51,8u60,9
  • Priority: P4
  • Status: Open
  • Resolution: Unresolved
  • Submitted: 2015-09-04
  • Updated: 2018-06-09
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.
Other
tbd_minorUnresolved
Related Reports
Relates :  
Relates :  
Description
The below test exercises the clause in JLS 18.5.2 stating that, where unchecked conversion was necessary for the arguments, the return type of the invocation must be erased.

    <T> T m(Class<T> arg1, Class<T> arg2) { return null; }

    void test(Class c1, Class<Class<String>> c2) throws Exception {
        m(c1, c2).newInstance();    // expected: error; actual: ok
        m(c1, c2).newInstance().length();    // expected: error; actual: error
    }

The erasure of the return type, T, is Object.  However, javac seems to be producing raw Class instead.  It appears that javac is inferring T=Class<String>, performing substitution on the return type, and *then* erasing to raw Class.  This is inconsistent with the spec, going back to JLS 3 (15.12.2.6), which makes clear that substitution of inference results only occurs in the case in which unchecked conversion was not necessary.
Comments
Based on the assumption that this issue is blocked by the spec issue JDK-6791481 JCK is OK to defer it to JDK 10. Corresponding JCK test will not be added to the product until spec bug is fixed.
21-11-2016

Propose deferring for 9: this is a longstanding problem, and addressing it risks breaking other aspects of how javac handles overload resolution (see discussion above). Will require extra scrutiny and bake time.
21-11-2016

Adjusted priority I=high: inconsistent with spec (I'm being generous here, since practical impact is low) L=low: only noticeable in rare use cases W=low: usually there's nothing to do���compiler lets the program through P4
21-11-2016

JDK-6791481 explores the longstanding discrepancies between javac and JLS on erasure of invocation types. May be relevant to this case.
17-12-2015

Similar test from Georgiy, this time with a 'throws' clause and a constructor call. class MyException extends Exception {} class MyDerivedException extends MyException {} class MyType<T> {} class Foo { public <E1 extends MyException> Foo(E1 e, MyType<String> a) throws E1 { throw e; } } public static void test(MyDerivedException e, MyType t) { try { new Foo(e, t); } catch (MyDerivedException e2) {} } // expected: uncaught exception MyException; actual: no error
04-09-2015

Also tested these variations, with the same outcome: <T> T m(Class<T> arg1, Class<? extends T> arg2) { return null; } <T> T m(Class<T> arg1, Class<? super T> arg2) { return null; }
04-09-2015

It is possible, given the longstanding javac behavior, that we should explore modifying JLS instead. However, there's a good principled reason for the specified behavior: given that we lose information when performing unchecked conversion, the inference constraints are "polluted". So it doesn't make sense to rely on them when making promises to clients about what they will get back.
04-09-2015