Generic constructor thrown type (constructor type variable) is not erased despite of unchecked conversion
Georgiy Rakov
georgiy.rakov at oracle.com
Fri Aug 28 15:33:38 UTC 2015
Hello,
let's consider following example.
class MyExceptionextends Exception {}
class MyDerivedExceptionextends MyException {}
class MyType<T> {
MyType(T t) {}
}
public class Test32 {
public static void test() {
try {
MyDerivedException e1 =new MyDerivedException();
Foo foo =new Foo(e1,new MyType(""));
}catch (MyDerivedException e2) {
}
}
}
class Foo {
public <E1 extends MyException> 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*_/.
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 generic and the method invocation does not
provide explicit type arguments, the invocation type is inferred as
specified in §18.5.2.
3. 18.5.2 contains following assertion:
If unchecked conversion was necessary for the method to be
applicable during constraint set reduction in §18.5.1, then the
parameter types of the invocation type of m are obtained by applying
a' to the parameter types of m's type, and the return type and
thrown types of the invocation type of m are given by the erasure of
the return type and thrown types of m's type. (jls-18.5.2-100-F.1-A)
and 18.2.2. contains following assertions:
A constraint formula of the form ‹S → T› is reduced as follows:
(jls-18.2.2-100) Otherwise, if Tis a parameterized type of the form
G|<|T_1 , ..., T_n |>|, and there exists no type of the form
G|<|...|>|that is a supertype of S, but the raw type Gis a supertype
of S, then the constraint reduces to /true/. (jls-18.2.2-100-D) The
fourth and fifth cases are implicit uses of unchecked conversion
(§5.1.9). These, along with any use of unchecked conversion in the
first case, may result in compile-time unchecked warnings, and may
influence a method's invocation type (§15.12.2.6). (jls-18.2.2-110)
3.1. During reduction constraint [new MyType("") -> MyType<String>] is
reduced to [MyType -> MyType<String>]. 3.2. [MyType -> MyType<String>]
is reduced to true according to jls-18.2.2-100-D. 3.3. Thus according to
jls-18.2.2-110 step 3.2 is considered as applying unchecked conversion.
3.4. Hence according to jls-18.5.2-100-F.1-Athe constructor exception
type should be erased that is E1 should be erased to MyException which
should have caused compilation failure, but compilation succeeds. 3.5.
So if I understand correctly javac behaves as if jls-18.5.2-100-F.1-A
specified that substitution a' is applied to m's thrown type first, and
only after that ctorthrown type is erased.This looks like a spec issue,
that is spec should have specified something like: "and the return type
and thrown types of the invocation type of m are given by the erasure of
the return type and thrown types of m2 where m2 is the result of
applying a' to m's type" (I guess the same is true for the return type).
Could you please tell if you agree that this is really a spec issue.
Thank you, Georgiy.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.openjdk.java.net/pipermail/compiler-dev/attachments/20150828/44062d77/attachment.html>
-------------- next part --------------
class MyException extends Exception {}
class MyDerivedException extends MyException {}
class MyType<T> {
MyType(T t) {}
}
public class Test32 {
public static void test() {
try {
MyDerivedException e1 = new MyDerivedException();
Foo foo = new Foo(e1, new MyType(""));
} catch (MyDerivedException e2) {
}
}
}
class Foo {
public <E1 extends MyException> Foo(E1 e, MyType<String> a) throws E1 {
throw e;
}
}
More information about the compiler-dev
mailing list