Code compiling with eclipse but not with javac

SceDev :

The code below compiles without any error with Eclipse but generates an error with Javac. It seems to be a compiler error but I don't know which one is right.

I would like to point out that I know how to correct this error by changing the code to make it work with both, but that is not the current topic. I would just like to know whether it's a java or an eclipse problem.

I try with Intellij but I have the same javac error.

Sample code to reproduce this error:

import java.util.ArrayList;
import java.util.List;

public class A<T extends B> {
    protected List<C> list = new ArrayList<>();

    class C {}

    public void createIO() {
        A<? extends B> x = null;
        List<A<? extends B>.C> y = x.list;
    }
}

class B {
}

JVM:

openjdk version "13-BellSoft" 2019-09-17
OpenJDK Runtime Environment (build 13-BellSoft+33)
OpenJDK 64-Bit Server VM (build 13-BellSoft+33, mixed mode, sharing)

With Eclipse, I don't have any errors. With Javac, I have the error:

A.java:13: error: incompatible types: List<A<CAP#1>.C> cannot be converted to List<A<? extends B>.C>
        List<A<? extends B>.C> y = x.list;
                                    ^
  where CAP#1 is a fresh type-variable:
    CAP#1 extends B from capture of ? extends B
Oleksandr Pyrohov :

The Eclipse compiler should show a compiler error like javac does. See Eclipse bug 539105.

javac behavior is correct and is aligned with the JLS:

And if a generic class C<T> has a non-generic member class D, then the member type C<String>.D is a parameterized type, even though the class D is not generic.

Thus, even though the inner class C is not generic, the:

A<? extends B>.C

is a parameterized type, where the type parameter of A is an unknown subtype of B. So, all rules on Generics apply to C as well in this context.

Thus, to eliminate compiler error, the type of y can be declared as follows:

List<? extends A<? extends B>.C> y = x.list;

But keep in mind that this won't allow you to add items to the list y (see PECS).

If it sounds complicated, try to think about it in scope of a simplified example:

List<Integer> l1 = new ArrayList<>();
List<Number > l2 = l1; // Error: incompatible types...

List<? extends Number> l3 = l1; // OK

Additional details:

The example in the question can be minimized to:

class A<T> {
    class C {}
    List<C> l1 = null;
    List<A<?>.C> l2 = l1; // Error: incompatible types...
    List<? extends A<?>.C> l3 = l1; // OK
}

List<A<?>.C> is a list of C of A of unknown type; C of arbitrary A can be added:

class A<T> {
    class C {}
    C c = new C();
    void foo(List<A<?>.C> list) {
        list.add(new A<String>().c);
        list.add(new A<Number>().c);
    }
}

See also:

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324710&siteId=1