question about JDK-8063054 (incorrect raw type warnings for method references)
B. Blaser
bsrbnd at gmail.com
Wed Mar 22 22:04:42 UTC 2017
On 18 March 2017 at 19:32, B. Blaser <bsrbnd at gmail.com> wrote:
> Hi,
>
> On 16 February 2017 at 11:35, Maurizio Cimadamore
> <maurizio.cimadamore at oracle.com> wrote:
>>
>>
>> On 16/02/17 02:33, Liam Miller-Cushon wrote:
>>>
>>> I think the fix might be as simple as replacing
>>> `!desc.getParameterTypes().head.isParameterized()` with something that
>>> handles capture variables.
>>
>> Hi Liam,
>> I think your analysis is correct - isParameterized would not work for
>> non-class types, so something else is required here. I believe intersection
>> types like Serializable & Comparable<Foo> might also end up with the same
>> problem - and, presumably, synthetic inner class types.
>>
>> Maurizio
Here are two more examples producing a warning that should probably be
avoided (am I right?). The first one involves an intersection type and
the second one an anonymous class:
class Test5 {
<B extends A & Box<Number>> void test(Box<B> b) {
Number n = b.<Number>map(Box::get).get();
}
interface Func<S,T> { T apply(S arg); }
interface Box<T> {
T get();
<R> Box<R> map(Func<T,R> f);
}
interface A {}
}
class Test6 {
interface Consumer<T> { void accept(T arg); }
interface Parent<P> { void foo(); }
interface Child extends Parent<String> {}
static <T> void m(T arg, Consumer<T> f) {}
public void test(Child c) { m(new Child() { public void foo() {}
}, Parent::foo); }
}
I had to write (here under) a method Types.isRaw() using a type
visitor to handle captured type variables, intersection types and
anonymous classes.
How does this look, did I miss anything?
Thanks,
Bernard
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java
b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java
@@ -227,6 +227,52 @@
};
// </editor-fold>
+ public boolean isRaw(Type t) {
+ return t != null && isRaw.visit(t);
+ }
+ // where
+ private final UnaryVisitor<Boolean> isRaw = new
UnaryVisitor<Boolean>() {
+ @Override
+ public Boolean visitType(Type t, Void ignored) {
+ return t.isRaw();
+ }
+
+ @Override
+ public Boolean visitClassType(ClassType t, Void ignored) {
+ if (t.isIntersection()) {
+ for (Type u: ((IntersectionClassType) t).getComponents())
+ if (isRaw(u))
+ return true;
+
+ return false;
+ }
+ else if (t.tsym.name.isEmpty()) {
+ // Anonymous
+ if (t.interfaces_field != null) {
+ for (Type i: t.interfaces_field)
+ if (isRaw(i))
+ return true;
+ }
+ else if (t.supertype_field != null &&
isRaw(t.supertype_field))
+ return true;
+
+ return false;
+ }
+
+ return t.isRaw();
+ }
+
+ @Override
+ public Boolean visitTypeVar(TypeVar t, Void ignored) {
+ return t.bound != null && isRaw(t.bound);
+ }
+
+ @Override
+ public Boolean visitCapturedType(CapturedType t, Void ignored) {
+ return t.bound != null && isRaw(t.bound);
+ }
+ };
+
// <editor-fold defaultstate="collapsed" desc="asSub">
/**
* Return the least specific subtype of t that starts with symbol
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java
b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java
@@ -2963,7 +2963,7 @@
if (that.getMode() == ReferenceMode.INVOKE &&
TreeInfo.isStaticSelector(that.expr, names) &&
that.kind.isUnbound() &&
- !desc.getParameterTypes().head.isParameterized()) {
+ types.isRaw(desc.getParameterTypes().head)) {
chk.checkRaw(that.expr, localEnv);
}
> Regarding Daniel's JBS comment, I think the condition should be made
> on isRaw() instead of isParameterized().
> The following example wouldn't produce any warning:
>
> class Test2 {
> interface Consumer<T> { void accept(T arg); }
> interface Parent<P> { void foo(); }
> interface Child extends Parent<String> {}
> static <T> void m(T arg, Consumer<T> f) {}
> public void test(Child c) { m(c, Parent::foo); }
> }
>
> Then, we could add a check on the bound of the captured type variable,
> as below. Liam's example wouldn't produce any warning but the
> following one would:
>
> class Test3 {
> void test(Box<Box> b) {
> Object o = b.<Object>map(Box::get).get();
> }
> interface Func<S,T> { T apply(S arg); }
> interface Box<T> {
> T get();
> <R> Box<R> map(Func<T,R> f);
> }
> }
>
> Any comment is welcome.
> Thanks,
> Bernard
>
> diff -r 43a83431f19d
> src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java
> --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java
> Wed Mar 15 15:46:43 2017 +0100
> +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java
> Sat Mar 18 19:01:02 2017 +0100
> @@ -2962,9 +2962,15 @@
>
> if (that.getMode() == ReferenceMode.INVOKE &&
> TreeInfo.isStaticSelector(that.expr, names) &&
> - that.kind.isUnbound() &&
> - !desc.getParameterTypes().head.isParameterized()) {
> - chk.checkRaw(that.expr, localEnv);
> + that.kind.isUnbound()) {
> +
> + Type t = desc.getParameterTypes().head;
> + if (t.isRaw() ||
> + t.getTag() == TYPEVAR &&
> + ((TypeVar)t).isCaptured() &&
> + ((TypeVar)t).bound.isRaw()) {
> + chk.checkRaw(that.expr, localEnv);
> + }
> }
>
> if (that.sym.isStatic() &&
> TreeInfo.isStaticSelector(that.expr, names) &&
More information about the compiler-dev
mailing list