JDK-8026527: Unchecked conversion is allowed by method type argument bound checking

Maurizio Cimadamore maurizio.cimadamore at oracle.com
Mon Sep 25 08:24:17 UTC 2017


Hi Bernard,
we are aware of the issue and the patch - the hard thing here is to 
establish as to whether the fix is doing more harm than good. As 
described in the comment you quote, a fix for this has been attempted, 
but then aborted in the light of these kinds of incompatibilities.

There is a number of type-system issues being worked on at the moment 
(at the spec level) [1] - I think it's best to defer any such point 
fixes after we have a clear picture of where the spec will land.

[1] - 
https://bugs.openjdk.java.net/browse/JDK-8078095?jql=labels%20%3D%20jls-types

Cheers
Maurizio


On 23/09/17 17:15, B. Blaser wrote:
> Hi,
>
> Following [1], I tried to investigate a bit more issue JDK-8026527.
>
> A JBS comment mention the following example, not far from [1]:
>
>    class Test {
>        @SuppressWarnings({"unchecked"})
>        Object parseEnumValue(Class<? extends Enum> enumType, String constName) {
>            return Enum.valueOf(enumType, constName);
>        }
>    }
>
> With:
>
>    public static <T extends Enum<T>> T valueOf(Class<T> enumType, String name);
>
> As it isn't clearly established if the latter should compile or not, I
> tried to follow JLS 9 §18.5.1 to see what's happening on the bound set
> of T:
>
>  From "Enum.valueOf()"    : T <: Enum<T>
>     (§18.5.1 + §18.1.3)
>  From formal parameters & actual arguments
> * Constraint formula     < enumType -> Class<T> >
>     (§18.5.1)
> * Reduced to             < Class<CAP#1 of ? extends Enum> -> Class<T>
>>    (§18.2.1 + §5.1.10)
> * Reduced to             < Class<CAP#1> <: Class<T> >
>     (§18.2.2)
> * Reduced to             < CAP#1 <= T >
>     (§18.2.3)
> * Reduced to             < CAP#1 = T >
>     (§18.2.3)
> * Reduced to bound       : CAP#1 = T
>     (§18.2.4)
>
>  From incorporation of complementary pairs of bounds
> * Constraint formula     < CAP#1 <: Enum<T> >
>     (§18.3.1)
> * Reduced to             : false
>     (§18.2.3)
>
> Which is similar to [1].
>
> So, I think this example should fail to compile as the others (the two
> from JDK-8026527 and the enhanced enums one [1]).
>
> My conclusion is that the fix, like here under, could perhaps be as
> straightforward as replacing "isSubtypeUnchecked()" by "isSubtype()"
> in "Resolve.rawInstantiate()" [2] per §15.12.2.2-3 and in
> "Infer.IncorporationBinaryOpKind.IS_SUBTYPE()" [3] per §18.2.3.
>
> What do you think?
>
> Thanks,
> Bernard
>
> [1] http://mail.openjdk.java.net/pipermail/amber-dev/2017-September/002075.html
> [2] http://hg.openjdk.java.net/jdk10/master/file/4fe50ead4783/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java#l582
> [3] http://hg.openjdk.java.net/jdk10/master/file/4fe50ead4783/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java#l1189
>
>
> diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java
> b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java
> --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java
> +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java
> @@ -1186,7 +1186,7 @@
>           IS_SUBTYPE() {
>               @Override
>               boolean apply(Type op1, Type op2, Warner warn, Types types) {
> -                return types.isSubtypeUnchecked(op1, op2, warn);
> +                return types.isSubtype(op1, op2);
>               }
>           },
>           IS_SAME_TYPE() {
> diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java
> b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java
> --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java
> +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java
> @@ -579,7 +579,7 @@
>                   List<Type> bounds =
> types.subst(types.getBounds((TypeVar)formals.head),
>                                                   pmt.tvars, typeargtypes);
>                   for (; bounds.nonEmpty(); bounds = bounds.tail) {
> -                    if (!types.isSubtypeUnchecked(actuals.head,
> bounds.head, warn))
> +                    if (!types.isSubtype(actuals.head, bounds.head))
>                           throw
> inapplicableMethodException.setMessage("explicit.param.do.not.conform.to.bounds",actuals.head,
> bounds);
>                   }
>                   formals = formals.tail;



More information about the compiler-dev mailing list