Search code examples
javagenericsjavac

Does this code exploit Java compiler generics verification limitations


While refactoring code I stumbled upon strange Java compiler (Oracle 1.8.0_101) behavior. My assumption is, if I replace all occurrences of List<T> by T (without using any methods from List) the code should compile, if it compiled before the change.

Now have a look at this code:

interface Mapper<T, U extends MapperProvider<U>> extends Function<T, List<U>> {}

interface MapperProvider<V> {
    Mapper<V, ?> provide();
}

private <V extends MapperProvider<V>> void use(V c) {
    use2(c.provide().apply(c));
}

private <W extends MapperProvider<W>> void use2(List<W> c) {
}

This code compiles. When I replace List<U> by U and List<W> by W:

interface Mapper<T, U extends MapperProvider<U>> extends Function<T, U> {}

interface MapperProvider<V> {
    Mapper<V, ?> provide();
}

private <V extends MapperProvider<V>> void use(V c) {
    use2(c.provide().apply(c));
}

private <W extends MapperProvider<W>> void use2(W c) {
}

it does not compile any more:

Error:(201, 17) java: method use2 in class Test cannot be applied to given types;
  required: W
  found: capture#1 of ?
  reason: inference variable W has incompatible bounds
    equality constraints: capture#1 of ?
    lower bounds: MapperProvider<capture#1 of ?>

which is correct from my point of view. use2 should be declared to receive MapperProvider<?>.

Why does the Java compiler treat the first version as legal?


Solution

  • It looks like Oracle thinks that this is a bug. I opened a bug report and Oracle confirmed: JDK-8172222