When i try to compile this cut-down example with a compiler from JDK 9, 10, or 11:
public class UpperBounder {
public static void main(String[] args) {
print(Stream.of("a", "z", "b").collect(Collectors.toCollection(TreeSet::new)));
}
static void print(Set<?> set) {
System.out.println(set);
}
}
I get this error:
error: incompatible types: inferred type does not conform to upper bound(s)
print(Stream.of("a", "z", "b").collect(Collectors.toCollection(TreeSet::new))); ^inferred: INT#1
upper bound(s): Collection<String>,Set<?>,Object
where INT#1 is an intersection type:
INT#1 extends Object,Set<?>,Collection<String>
When i try to compile it with JDK 1.8.0_121, i get a different error. But when i or a colleague try to compile it with JDK 1.8.0_05, 1.8.0_20, 1.8.0_40, or 1.8.0_45, it compiles fine!
Replacing TreeSet::new with () -> new TreeSet<>() makes this compile without errors on all versions.
I think this program is clearly sound: the argument to print will be a TreeSet<String>, which conforms to Set<?>. Moreover, the error message makes no sense to me: an intersection type which is Object, Set<?>, and Collection<String> should conform to upper bounds which are Collection<String>, Set<?>, and Object!
What is going on? Is this a bug? Or is this how type inference is supposed to work? Why did it work before? How can i make it work again (without using a lambda instead of a method reference)?
javac 10.0.2, but not Eclipse's compilerecj 3.14.0.v20180528- NPras