Incoherent invocation type inference?
B. Blaser
bsrbnd at gmail.com
Thu Jan 19 13:44:04 UTC 2017
Hi,
2017-01-15 12:45 GMT+01:00 Remi Forax <forax at univ-mlv.fr>:
> Inference of 0-arity methods in Java is due to the fact that generics were introduced after the collection API in Java, and an explicit goal of the specification of generics was to be able to retrofit classes of java.util.
>
> An unsafe warning means that you may get a ClassCastException at runtime.
>
> In the collection API, you have methods like Collections.emptyList() that has to return different types depending on the calling context.
> Calling those methods should not emit a warning because you can not have a CCE at runtime, if you call a method that takes an E will have get an UnsupportedException, if you call a methods that returns an E you will get an IndexOutOfBoundsException or a NoSuchElementException. So you may get a lot of different exceptions but not a CCE, so a call to Collections.emptyList() is safe (with the current definition of what safe means) and the compiler should not trigger any warning.
>
As noted by Maurizio further in the thread, a warning might be
interesting when a retun value is expected and a naked type variable
is returned with no constraint given by the actual arguments; because
the invoked method wouldn't know about the return type constraint. The
collection API you mentioned wouldn't probably be concerned, as most
0-arity methods don't return any naked type variable.
Nevertheless, List<E> declares an interesting method: <T> T[] toArray(T[] a);
In the current implementation of ArrayList, if we write something like:
List<String> l = new ArrayList<String>();
l.add("test");
String[] sa = new String[1];
sa = l.toArray(null); // NullPointerException
Integer[] ia = new Integer[1];
ia = l.toArray(null); // NullPointerException
... we get a NullPointerException. We could imagine another
implementation that would invoke "Object[] toArray()" if "a==null". In
that case we would get a ClassCastException. In all cases, this piece
of code will fail at runtime with any exception. Then, javac could
probably emit also a warning in this situation by updating the rule as
follows:
"emit a Lint warning if a return value is expected and the return type
T is a naked type variable or an array of a naked type variable and no
constraint is given by the actual arguments".
The following draft is a suggestion for the implementation of this
rule (Infer.instantiateMethod() upon rev. b6960e2da008).
What's your opinion on that?
Thanks,
Bernard
> C# is different because if you declare a static field instead of having one static value, you have one static value by type argument,
> so for C#, it makes sense to force users to specify the type argument given that the returned value will be different.
>
> The problem of the code of Bernard is not related to the inference, the problem is the unsafe cast in the implementation, if you use an unsafe cast, then you may have a ClassCastException at runtime. It's as simple as that.
>
> regards,
> Rémi
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
@@ -182,6 +182,30 @@
final InferenceContext inferenceContext = new
InferenceContext(this, tvars); //B0
inferenceException.clear();
try {
+ Type elemResType = mt.restype;
+ while (elemResType.hasTag(ARRAY)) {
+ elemResType = ((ArrayType)elemResType).elemtype;
+ }
+ if (resultInfo != null && resultInfo.pt != Type.noType &&
elemResType.hasTag(TYPEVAR)) {
+ int nbConstraints = 0;
+ if (mt.argtypes.length() <= argtypes.length()) {
+ for (int i=0; i<mt.argtypes.length(); i++) {
+ Type pType = mt.argtypes.get(i);
+ Type aType = argtypes.get(i);
+ if (pType.contains(elemResType) && aType !=
syms.botType)
+ nbConstraints++;
+ }
+ }
+ if (nbConstraints == 0) {
+ chk.warnUnchecked(env.tree.pos(),
+ "unchecked.invocation.type.inference",
+ Kinds.kindName(msym),
+ msym.name,
+ Kinds.kindName(msym.location()),
+ msym.location());
+ }
+ }
+
DeferredAttr.DeferredAttrContext deferredAttrContext =
resolveContext.deferredAttrContext(msym,
inferenceContext, resultInfo, warn);
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties
b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties
@@ -1748,6 +1748,10 @@
required: {2}\n\
found: {3}
+# 0: symbol kind, 1: name, 2: symbol kind, 3: symbol
+compiler.warn.unchecked.invocation.type.inference=\
+ unchecked invocation type inference: {0} {1} in {2} {3} is
missing constraints from actual arguments
+
# 0: type
compiler.warn.unchecked.generic.array.creation=\
unchecked generic array creation for varargs parameter of type {0}
More information about the compiler-dev
mailing list