JDK-8133936 : The return type of instance creation expression with diamond and class body should be anonymous class type
  • Type: Bug
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 9
  • Priority: P2
  • Status: Closed
  • Resolution: Not an Issue
  • Submitted: 2015-08-19
  • Updated: 2017-03-13
  • Resolved: 2015-09-01
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.
JDK 9
9Resolved
Related Reports
Relates :  
Relates :  
Description
let's consider following example:

class List<T> {
    List() {}
    List<T> getThis() {
        return new List();
    }
}

class Foo<T> {
    public Foo(T a1){}
}

public class Test25  {
    public static <T> List<T> m1(T item) {
        List l = new List();
        return l;
    }
    public static <U> void m2(List<U> list1, List<U> list2) { }
    public static void test() {
        m2(new List<Foo<String>>(),  m1(new Foo<>("str"){ }).getThis());
    }
}

This example compiles successfully on JDK9b75. But according to my understanding the compilation should have failed. The reasons for this are presented below:

1. JDK-8073593 specifies following assertion:

    ***If C is an anonymous class, then the chosen constructor is the constructor of the anonymous class. The return type is the anonymous class type.***

current JLS 9 15.9.1 spec defines following assertion:

    The type of the class instance creation expression is the return type of the chosen constructor, as defined above.

so together these assertions lead to the fact that the type of instance creation expression "new Foo<>("str"){ } " is anonymous class type, let's denote it as "anonymous Foo<String>".

2. Thus when m1 is invoked, that is "m1(new Foo<>("str"){ })", the invocation return type is List<anonymous Foo<String>>.

3. Hence when getThis is invoked, that is "m1(new Foo<>("str"){ }).getThis()", the invocation return type is List<anonymous Foo<String>> as well.

4. Finally when m2 method is invoked type inference cause two equality constraints to be created that is: U = Foo<String> and U = (anonymous Foo<String>), together they should lead to compilation failure, but compilation succeeds.

This seems to be a javac bug.

Please note, that if diamond is replaced with String type argument, that is "new Foo<String>("str"){ }" the compilation fails as expected:

    Error:(19, 9) java: method m2 in class Test25 cannot be applied to given types;
      required: List<U>,List<U>
      found: List<Foo<java.lang.String>>,List<<anonymous Foo<java.lang.String>>>
      reason: inference variable U has incompatible equality constraints <anonymous Foo<java.lang.String>>,Foo<java.lang.String>
Comments
Step 2 is incorrect. There's a subtle difference between the the stand-in method 'mj', used for type inference, and the selected constructor. - "The return type of mj is theta_j applied to ***D***<F1,...,Fp>" - "If C is an anonymous class, then the chosen constructor is the constructor of the anonymous class. The return type is the anonymous class type." Inference makes use of mj -- see JLS 18.2.1: "For a class instance creation expression, the corresponding "method" used for inference is defined in ��15.9.3". So: 'new Foo<>("str"){ }' has type [anonymous Foo<String>] but 'm1(new Foo<>("str"){ })' infers T=Foo<String>, so has type Foo<String> Thus, no error. This is pretty messy, but there's a reason for it: we can't really talk about a class type '[anonymous Foo<___>]' until we can fill in the blank. In order to fill in the blank, we have to do type inference. And in order to do type inference, we have to build constraints based on the type of the anonymous instance creation. Hence, we give type inference the best information we have at the time -- that the expression will return a Foo<alpha> for some alpha. Only later when inference is done can we go back and say, "actually, it's not just a Foo<String>, it's a [anonymous Foo<String>]."
01-09-2015