Non generic constructor thrown type (class type variable) is not erased despite of unchecked conversion

Georgiy Rakov georgiy.rakov at oracle.com
Fri Aug 28 13:02:43 UTC 2015


Hello,

let's consider following example.

    class MyException extends Exception {}class MyDerivedException
    extends MyException {}class MyType<T> {MyType(T t) {}}public class
    Test31 {public static void test() {try {MyDerivedException e1 = new
    MyDerivedException();Foo foo = new Foo<MyDerivedException>(e1, new
    MyType(""));} catch (MyDerivedException e2) {}}}class Foo<E1 extends
    MyException> {public Foo(E1 e, MyType<String> a) throws E1 {throw e;}}

It compiles successfully on JDK9b78. Now let's consider reasoning 
presented below.

1. According to following assertion, 15.12.2 is used in order to 
determine the constructor thrown types:

    ***If C is not an anonymous class,*** let T be the type denoted by C
    followed by any class type arguments in the expression. The process
    specified in §15.12.2, modified to handle constructors, is used to
    select one of the constructors of T and /_*determine its throws
    clause*_/ [jls-15.9.3-120-B.1
    <https://wiki.se.oracle.com/display/JPG/Coverage+of+diamond+with+anonymous+classes+feature#Coverageofdiamondwithanonymousclassesfeature-jls-15.9.3-120-B.1>]

2. According to my understanding the types in throws clause are 
determined in the last subsection of 15.12.2, that is in 15.12.2.6, 
which states:

    If the chosen method is not generic, then [jls-15.12.2.6-100-C
    <https://baloo.ru.oracle.com/jenkins/job/jck9-lang/lastSuccessfulBuild/artifact/build/out/htmlout/jls-15.html#jls-15.12.2.6-100-C>]:

    If /_*unchecked conversion*_/ was necessary for the method to be
    applicable, the parameter types of the invocation type are the
    parameter types of the method's type, and the return type and
    /_*thrown types*_/ are given by the erasures of the return type and
    thrown types of the method's type [jls-15.12.2.6-100-C-A
    <https://baloo.ru.oracle.com/jenkins/job/jck9-lang/lastSuccessfulBuild/artifact/build/out/htmlout/jls-15.html#jls-15.12.2.6-100-C-A>].

3. So unchecked conversion is necessary in order for the constructor to 
be applicable because expression 'new MyType("")' of a raw type is 
passed to parameterized parameter 'MyType<String> a'.

Could you please tell if I understand correctly that JLS implies that 
when erasing constructor thrown types, the actual type which is erased 
is not E1 but E1 with following substitution applied [E1 := 
MyDerivedException]. According to my understanding JLS doesn't specify 
this explicitly, but as I see it such clarification could be useful. 
Could you please also tell if you think it's worth filing P4 issue about 
this.

Thank you,
Gosha.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.openjdk.java.net/pipermail/compiler-dev/attachments/20150828/00feb6ad/attachment-0001.html>
-------------- next part --------------
class MyException extends Exception {}

class MyDerivedException extends MyException {}


class MyType<T> {
    MyType(T t) {}
}

public class Test31  {
    public static void test() {
        try {
            MyDerivedException e1 = new MyDerivedException();

            Foo foo = new Foo<MyDerivedException>(e1, new MyType(""));
        } catch (MyDerivedException e2) {
        }
    }
}

class Foo<E1 extends MyException> {
    public Foo(E1 e, MyType<String> a) throws E1 {
        throw e;
    }
}


More information about the compiler-dev mailing list