10

I am running into a very strange issue when applying a method reference to the second type in an intersection type. Here is a minimal test case:

class LambdaTest {

    interface A {}

    interface B {
        B doIt();
    }

    static class AB implements A, B {
        public B doIt() {
            return this;
        }
    }

    static <E extends A & B> void run(E e) {
        Collections.singleton(e).stream().map(B::doIt);
    }

    public static void main(String[] args) {
        run(new AB());
    }
}

This code compiles but fails in run at runtime with error:

java.lang.invoke.LambdaConversionException: Invalid receiver type interface LambdaTest$A; not a subtype of implementation type interface LambdaTest$B

This issue even occurs when explicitly specifying the type of the lambda:

static <E extends A & B> void run(E e) {
    final Function<E, B> doIt = B::doIt;
    Collections.singleton(e).stream().map(doIt);
}

Apparently the lambda is expected to take specifically the first type in the intersection and not the second. Sure enough, changing the method signature of run as follows makes the error go away:

static <E extends B & A> void run(E e) {

Interestingly, a couple other minor changes also fix the error. Calling a method in Object works, presumably because any A must also have that method:

Collections.singleton(e).stream().map(B::toString);

Also, pulling the function reference out of run fixes the error:

static <E extends A & B> void run(E e, Function<B, ?> f) {
    Collections.singleton(e).stream().map(f);
}

public static void main(String[] args) {
    run(new AB(), B::doIt);
}

Finally, converting the method reference to a regular lambda fixes the issue:

Collections.singleton(e).stream().map(x -> x.doIt());

So it seems that there is an issue specifically with method references. The compiler allows any method reference that is valid on the intersection type. However, the implementation assumes that the method reference will take the first type of the intersection, A, even if the type of the lambda is explicitly specified. The implementation then checks whether the method is available on type A and if not, fails.

Is my analysis correct? Is this behavior intentional or is it a bug?

Reinstate Monica
  • 2,420
  • 14
  • 23
  • Which specific version of Java is it? u45, u51? Note: I can reproduce with u51 here – fge Jul 29 '15 at 22:12
  • 3
    Sorry, I should have specified. I'm using OpenJDK version 1.8.0_45-internal. – Reinstate Monica Jul 29 '15 at 22:17
  • 2
    [JDK-8058112](https://bugs.openjdk.java.net/browse/JDK-8058112) seems to be related to your problem, though it's marked as resolved... – Tagir Valeev Jul 30 '15 at 02:38
  • 2
    @Tagir Valeev: the most recent jdks solve the problem as far as covered by the example code in the bug report but unfortunately it seems to be incomplete as the code of this question still triggers the bug… – Holger Jul 30 '15 at 10:01
  • The code in the question seems to work fine in 8u101. – Martin Apr 10 '17 at 15:09

0 Answers0