JDK-8138954 : Inference failure when using a constructor reference
  • Type: Bug
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 8u60,9
  • Priority: P4
  • Status: Open
  • Resolution: Unresolved
  • OS: linux
  • CPU: x86
  • Submitted: 2015-09-27
  • Updated: 2017-02-03
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.
Other
tbd_majorUnresolved
Related Reports
Blocks :  
Duplicate :  
Relates :  
Relates :  
Relates :  
Description
FULL PRODUCT VERSION :
javac -version
javac 1.8.0_60


ADDITIONAL OS VERSION INFORMATION :
Linux desktop 4.1.6-1-ARCH #1 SMP PREEMPT Mon Aug 17 08:52:28 CEST 2015 x86_64 GNU/Linux
Linux lab 3.13.0-63-generic #103-Ubuntu SMP Fri Aug 14 21:43:30 UTC 2015 i686 i686 i686 GNU/Linux

A DESCRIPTION OF THE PROBLEM :
The attached code does not compile. It should. It did at least in 1.8.0_25


REGRESSION.  Last worked in version 8u40

ADDITIONAL REGRESSION INFORMATION: 
This code compiled and worked fine in 1.8.0_25


ERROR MESSAGES/STACK TRACES THAT OCCUR :
Error:(15, 20) java: method unmodifiableList in class java.util.Collections cannot be applied to given types;
  required: java.util.List<? extends T>
  found: java.util.Collection<Main>
  reason: cannot infer type-variable(s) E
    (actual and formal argument lists differ in length)

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.stream.Collectors;

class Main {

    static Collection<Main> list = null;

    public static void main(String[] args) {
        Collections.unmodifiableList(list.stream().collect(Collectors.toCollection(ArrayList::new)));
    }
}

---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.stream.Collectors;

class Main {

    static Collection<Main> list = null;

    static ArrayList create() {
        return new ArrayList();
    }

    public static void main(String[] args) {
        Collections.unmodifiableList(list.stream().collect(Collectors.toCollection(Main::create)));
    }
}



Comments
A couple of similar test cases from JDK-8173176: import java.util.*; import java.util.stream.*; class JDK8173176 { public void test(Stream<String> strings) { Set<String> s = Collections.unmodifiableSet(strings.collect(Collectors.toCollection(TreeSet::new))); } } --- import java.util.function.*; abstract class Test { void m() { List<String> stringSet = id(toCollection(s -> new ArrayList<>())); } static <U> List<U> id(List<? extends U> l) { return null; } static <C extends Collection<String>> C toCollection(Function<String, C> collectionFactory) { return null; } }
03-02-2017

Reported javac behavior is consistent with the spec. Progress on spec improvement is blocked by JDK-8039222. When we've defined the proper approach for "merging" wildcard-parameterized types, we can revisit incorporation here and see if there's an opportunity for useful improvement to the algorithm.
06-01-2017

A missing piece of my above analysis: the method reference is inexact (method is generic). Thus, we need to do some reasoning about the 'apply' *before* getting constraints from the method reference. Specifically: - Applicability testing for 'apply' tries to resolve { b <: Object, c <: Collection<b>, c <: Object } (and succeeds, b = Object, c = Collection<Object>) - Applicability testing for 'wrap' needs to determine whether the 'apply' invocation is compatible with 'List<? extends String>'. Details and timing are specified in JDK-8069544. To assert compatibility, we must resolve { b <: Object, c <: List<? extends String>, c <: Collection<b> } However, incorporation has no support for passing extra information from the wildcard to 'b'. If b=Object, there's no satisfactory solution for 'c'.
06-01-2017

Bug was introduced by JDK-8069545.
09-12-2015

Applicability testing for 'apply' should produce: this::makeList --> Supplier<c> { List<a> <: c, c <: Collection<b>, a = b } Invocation typing should the produce: c --> List<? extends String> { a <: String, b <: String, c <: List<? extends String>, List<a> <: c, c <: Collection<b>, a = b } Resolving: a = String b = String c = List<String>
09-12-2015

Simplified test case: <A> List<A> makeList() { return new ArrayList<>(); } <B,C extends Collection<B>> C apply(Supplier<C> f) { return f.get(); } void wrap(List<? extends String> list) {} void test() { wrap(apply(this::makeList)); }
09-12-2015

Attached test case was compiled on Windows 7 with the following : JDK 8u45 - Pass JDK 8u51 -Pass JDK 8u60 - Fail JDK 9ea b78 - Fail Following is the compile time error: ------------------------------------------------------------------------------------------------------- D:\TestCases\src>javac TestCollectionUnmodifiable.java TestCollectionUnmodifiable.java:10: error: method unmodifiableList in class Coll ections cannot be applied to given types; Collections.unmodifiableList(list.stream().collect(Collectors.to Collection(ArrayList::new))); ^ required: List<? extends T> found: Collection<TestCollectionUnmodifiable> reason: cannot infer type-variable(s) E (actual and formal argument lists differ in length) where T,E are type-variables: T extends Object declared in method <T>unmodifiableList(List<? extends T>) E extends Object declared in class ArrayList 1 error ---------------------------------------------------------------------------------------------------------------- Moving across to dev- team for action.
06-10-2015

There seems to be some issues with glb - inferred type is this: java.lang.Object&java.util.List<? extends java.lang.Object>&java.util.Collection<Main> This is the result of calling glb on the following types: glb(Object, List<? extends Object>, Collection<Main>) This seems to be compliant with the spec - but then the bound check fails as javac cannot prove that the above intersection type is a subtype of Collection<Main>. Note that the intersection type provides two paths to get there: List<? extends Object> <: Collection<Main> --> Fail Collection<Main> <: Collection<Main> --> Ok The implementation of types.asSuper() picks the first supertype that is a subclass of Collection, meaning the subtyping check will only perform the first branch. It is likely that, following some changes, the order of bounds was simply swapped, and javac started to fail in this way.
06-10-2015