Community
Participate
Working Groups
Always reproducible. Steps to reproduce: 1. Create EclipseBug.java: import java.util.*; import java.util.function.*; public class EclipseBug { static class Test<T,A,R> { public Test(Supplier<A> supplier, BiConsumer<A, T> accumulator, BinaryOperator<A> combiner, Function<A, R> finisher) {} } static class Box<T> { T a; public Box(T t) {this.a = t;} } public static <T> Test<T, ?, Optional<T>> onlyOne() { return new Test<>(() -> new Box<Optional<T>>(null), //return new Test<T, Box<Optional<T>>, Optional<T>>(() -> new Box<Optional<T>>(null), (box, t) -> box.a = box.a == null ? Optional.of(t) : Optional.empty(), (box1, box2) -> box1.a == null ? box2 : box2.a == null ? box1 : new Box<>(Optional.empty()), box -> box.a == null ? Optional.empty() : box.a); } } 2. Compile: java -jar org.eclipse.jdt.core_3.11.1.v20150902-1521.jar -8 EclipseBug.java Expected: successful compilation Actual: compilation error: ---------- 1. ERROR in L:\Lan\Projects\t\EclipseBug.java (at line 16) return new Test<>(() -> new Box<Optional<T>>(null), //return new Test<T, Box<Optional<T>>, Optional<T>>(() -> new Box<Optional<T>>(null), (box, t) -> box.a = box.a == null ? Optional.of(t) : Optional.empty(), (box1, box2) -> box1.a == null ? box2 : box2.a == null ? box1 : new Box<>(Optional.empty()), box -> box.a == null ? Optional.empty() : box.a); ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Cannot infer type arguments for Test<> ---------- 1 problem (1 error) Possible work-around: explicit specification of type arguments (as in outcommented line) Regression: compiles fine with org.eclipse.jdt.core_3.10.2.v20150120-1634.jar and org.eclipse.jdt.core_3.10.0.v20140902-0626.jar. Also compiles fine with Javac 8u20, 8u31, 8u45, 9ea-b76. Probably related to Bug#481649.
Thanks. The error is reported since 4.5M3. This milestone contains a major clean-up of Java 8 type inference & overload resolution - including a number of JLS changes after Java 8 GA. From this, there is no easy way for telling whether the behavioral change is driven by such a spec change or a new implementation bug. Will investigate.
I've simplified the example and made type parameter names unique for easier reasoning: //--- import java.util.*; import java.util.function.*; public class EclipseBug { static class Test<T,A,R> { public Test(Supplier<A> supplier, BiConsumer<A, T> accumulator, BinaryOperator<A> combiner, Function<A, R> finisher) {} } static class Box<B> { B a; public Box(B b) {this.a = b;} } public static <S> Test<S, ?, Optional<S>> onlyOne() { return new Test<>( () -> new Box<Optional<S>>(null), (box, t) -> Optional.empty(), (box1, box2) -> new Box<>(Optional.empty()), // inner box -> box.a); } } //--- Dump of an comprehensive debug session: Here's the inference context before invocation type inference for the outer diamond: Inference Context (applicability inferred) (strict) Inference Variables: T'#0 : S A'#1 : NOT INSTANTIATED R'#2 : java.util.Optional<S> B#3 : NOT INSTANTIATED Initial Constraints: ⟨Optional.empty() → B#3⟩ Type Bounds: TypeBound T'#0 = S TypeBound A'#1 :> EclipseBug.Box<java.util.Optional<S>> Dependency A'#1 :> EclipseBug.Box<B#3> TypeBound R'#2 = java.util.Optional<S> The problem is, we have no useful constraints / bounds for B#3, which represents the type parameter for Box in the inner diamond. From there the first round of resolution (A'#1, T'#0) produces this solution: TypeBound T'#0 = S TypeBound A'#1 = EclipseBug.Box<? extends java.lang.Object> TypeBound R'#2 = java.util.Optional<S> TypeBound B#3 = java.lang.Object Incorporation of corresponding C-set constraints in this round yields: Type Bounds: TypeBound T'#0 = S TypeBound A'#1 :> EclipseBug.Box<java.util.Optional<S>> Dependency A'#1 :> EclipseBug.Box<B#3> TypeBound R'#2 :> capture#1-of ? extends java.lang.Object TypeBound R'#2 = java.util.Optional<S> The second round (R'#2, A'#1) fails incorporation due to this unsatisfiable constraint: ⟨java.util.Optional<S> :> capture#1-of ? extends java.lang.Object⟩ as derived from TypeBound R'#2 = java.util.Optional<S> TypeBound R'#2 :> capture#1-of ? extends java.lang.Object The latter type bound is derived from this (good) constraint: ⟨(<no type> box) -> box.a → java.util.function.Function<A'#1,R'#2>⟩ but with dubious substitution A'#1=Box<? extends Object> to yield: ⟨(<no type> box) -> box.a → Function<Box<? extends Object>,R'#2>⟩ The substitution results from the first round of resolution.
To rule out special impact of diamonds, I further refactored the example to: //--- import java.util.*; import java.util.function.*; public class EclipseBug { static class Test<T,A,R> { public Test(Supplier<A> supplier, BiConsumer<A, T> accumulator, BinaryOperator<A> combiner, Function<A, R> finisher) {} static <T2,A2,R2> Test<T2,A2,R2> create(Supplier<A2> s, BiConsumer<A2, T2> c, BinaryOperator<A2> o, Function<A2, R2> f) { return new Test<>(s,c,o,f); } } static class Box<B> { B a; public Box(B b) {this.a = b;} static <B2> Box<B2> create(B2 b) { return new Box<>(b); } } public static <S> Test<S, ?, Optional<S>> onlyOneFactory() { return Test.create( () -> new Box<Optional<S>>(null), (box, t) -> Optional.empty(), (box1, box2) -> Box.create(Optional.empty()), box -> box.a); } } //--- Still the same failure. Adding explicit type arguments to either create() invocation lets inference succeed. I still haven't a clue how JLS would let us find the solution. Obviously, the connection must be made via the ivar for A2, for which we have the following information: Box<Optional<S>> <: A2#1 Box.create(Optional.empty()) → A2#1 We have no information from the target type, where A2 is substituted to '?'. The problem can be further described as failure to lift a deeply nested inference (Optional.empty()) into the outer-most inference. This may be aggravated by the fact that A2#1 only ever occurs in the position as an upper bound.
Bug has been fixed meanwhile (in 4.6 M6) via bug 487746. Quoting a comment from the other bug: (In reply to Stephan Herrmann from bug 487746 comment #20) > For posterity: this fix was part of a sequence of attempts to properly > implement https://bugs.openjdk.java.net/browse/JDK-8038747 (a spec change after Java 8 GA) *** This bug has been marked as a duplicate of bug 487746 ***