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