JDK-8148354 : Errors targeting functional interface intersection types
  • Type: Bug
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 8,9
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2016-01-21
  • Updated: 2019-08-02
  • Resolved: 2018-05-18
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 11
11 b15Fixed
Related Reports
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Description
FULL PRODUCT VERSION :
java version "1.8.0_72"
Java(TM) SE Runtime Environment (build 1.8.0_72-b15)
Java HotSpot(TM) 64-Bit Server VM (build 25.72-b15, mixed mode)


A DESCRIPTION OF THE PROBLEM :
Type inference fails for certain intersection types. See attached Java Code: the method consume is defined with a type variable

<T extends Object & Serializable & Consumer<String>>

(this definition is only for demonstration purposes, usually one would only declare

<T extends Serializable & Consumer<String>>

The method is called using a method reference

consume(this::process, ...

The compilation fails and (because of the exact declaration) says that the method reference is interpreted as Consumer<String> (which is correct in principle), but cannot be converted to "T extends Object,Serializable,Consumer<String>".

The Eclipse compiler compiles and runs this code without problems.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The intersection type should be automatically inferred from the method's type variable.

ERROR MESSAGES/STACK TRACES THAT OCCUR :
GenericsTest.java:15: error: incompatible types: cannot infer type-variable(s) T
        consume(this::process, "Hello World");
               ^
    (argument mismatch; Consumer<String> cannot be converted to INT#1)
  where T is a type-variable:
    T extends Object,Serializable,Consumer<String> declared in method <T>consume(T,String)
  where INT#1 is an intersection type:
    INT#1 extends Object,Serializable,Consumer<String>
1 error


REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.io.Serializable;
import java.util.function.Consumer;

public class GenericsTest {
    public <T extends Object & Serializable & Consumer<String>> void consume(final T _cons,
            final String _s) {
        _cons.accept(_s);
    }

    public void process(final String _o) {
        System.out.println(_o);
    }

    public void testCompile() {
        consume(this::process, "Hello World");
    }
}
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Adding a cast:

        consume((Serializable & Consumer<String>) this::process, "Hello World");

makes the code compile.


Comments
the related example above seems to be due to a different bug. I have created JDK-8202597 to track it
03-05-2018

Related: class JDK8148354 { interface I {} interface J { void foo(); } public void test() { Object o1 = (I & J) System::gc; Object o2 = (Object & J) System::gc; // error Object o3 = (Object & I & J) System::gc; // error } } javac believes that Object is not allowed here, but it is: - "An intersection type that induces a notional functional interface" is a functional interface type (JLS 9.8) - "If Ck is Object, a notional interface is induced" -- where Ck is derived by mapping each intersection component to its most specific superclass type and then choosing the most specific of these class types -- in these cases, that's Object (JLS 4.9)
07-12-2017

Slightly simplified: class JDK8148354 { interface I {} interface J { void foo(); } <T extends Object & I & J> void consume(T arg) { } public void test() { consume(System::gc); } } Compiles without error with `T extends Object & J` or `T extends I & J`.
07-12-2017

Different behaviours observed on Eclipse and javac command. Eclipse compiles the above code properly, where as javac doesn't and gives error. Verified in the below versions 8uxx - Fail (All the versions of 8 including 8u72) 9 ea b- 102 - Fail
27-01-2016