JDK-8026527: Unchecked conversion is allowed by method type argument bound checking
B. Blaser
bsrbnd at gmail.com
Sat Sep 23 16:15:46 UTC 2017
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