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

Dan Smith daniel.smith at
Thu Sep 3 20:22:48 UTC 2015

I think this one also comes down to JDK-8034925: what is the "return type and thrown types of the method's type" ( when the "method" is actually a constructor?  It looks like the answer has to be: the type of the declaration, *after* substituting the class type arguments.  So erasure is going to be applied to MyDerivedException, not the type variable E1.

For comparison, here's how this works when working with methods of a generic class:

public class ErasedThrows<T extends Exception> {

    static class CustomException extends Exception {
        void foo() {}

    T m(Iterable<String> arg) throws T { return null; }

    static void test(Iterable i) throws CustomException {
        new ErasedThrows<CustomException>().m(i).foo();
        // m, as a member of ErasedThrows<CustomException>, has signature:
        //        CustomException m(Iterable<String> arg) throws CustomException
        // this gets erased, but that doesn't change the return or thrown type -- neither are Exception



> On Aug 28, 2015, at 7:02 AM, Georgiy Rakov <georgiy.rakov at> wrote:
> 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 <>]
> 2. According to my understanding the types in throws clause are determined in the last subsection of 15.12.2, that is in, which states:
> If the chosen method is not generic, then [jls- <>]:
> 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- <>].
> 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: <>

More information about the compiler-dev mailing list