-
Bug
-
Resolution: Fixed
-
P4
-
6u22
15.9 says the thrown types of a class instance creation expression include E, where "E is listed in the throws clause of the type of the constructor that is invoked". This doesn't account for the possibility that E may be a type variable (one of the type parameters of the constructor).
The text needs to be clarified, and 15.9.3 in particular needs to describe how the throws clause may be derived from inferred type arguments. It's particularly unclear whether E should be erased due to unchecked argument conversion, as in 15.12.2.6.
I believe the scope of this problem is restricted to the case of type variables appearing as thrown types. 8.1.2 prohibits exception classes from being generic, so we can never have throws MyException<T>, etc.
I wrote a test to see what implementations did. The results demonstrate that the correct behavior is very poorly understood.
/**
* 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: E (!)
* 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: E (!)
* Eclipse: RuntimeException
*/
void m6() {
Iterable i = java.util.Collections.EMPTY_LIST;
new <RuntimeException>UncheckedInvocation(i);
}
}
The text needs to be clarified, and 15.9.3 in particular needs to describe how the throws clause may be derived from inferred type arguments. It's particularly unclear whether E should be erased due to unchecked argument conversion, as in 15.12.2.6.
I believe the scope of this problem is restricted to the case of type variables appearing as thrown types. 8.1.2 prohibits exception classes from being generic, so we can never have throws MyException<T>, etc.
I wrote a test to see what implementations did. The results demonstrate that the correct behavior is very poorly understood.
/**
* 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: E (!)
* 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: E (!)
* Eclipse: RuntimeException
*/
void m6() {
Iterable i = java.util.Collections.EMPTY_LIST;
new <RuntimeException>UncheckedInvocation(i);
}
}
- relates to
-
JDK-6791481 15.12.2.6: Excessive erasure of return/thrown types is specified
-
- Open
-
-
JDK-8034925 15.12.2: Clarify mismatches when overload resolution is re-used by 15.9 and 15.13
-
- Open
-
-
JDK-7015430 Incorrect thrown type determined for unchecked invocations
-
- Closed
-