JDK-8078592 : Compiler fails to reject erroneous use of diamond with anonymous classes involving "fresh" type variables.
  • Type: Bug
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 9
  • Priority: P4
  • Status: Closed
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2015-04-24
  • Updated: 2015-06-04
  • Resolved: 2015-05-04
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
9 b64Fixed
Related Reports
Duplicate :  
Relates :  
Description
This issue was reported by Georgiy Rakov in compiler-dev mailing list:

// ---------------------------------- 8< -----------------------------

Let's consider following example:

    class B<V> {}

    class Foo<E extends B<E>> {
        public Foo<E> complexMethod(E a) { return this; }
    }

    public class Test65  {
        public static void check() {
            Foo t4 = new Foo<>() {
            };
        }
    }

This code successfully compiles on JDK9b60. However according to my understanding the compilation should have failed as per new spec. Could you please tell if this understanding is correct.

The reasons why I think that the compilation should have failed are presented below.

E is inferred as B<Y>, where Y is a fresh type variable with the upper bound B<Y>.  If this is correct the given code should cause compilation failure according to following new assertions presented in the JDK-8073593 issue comment:

    ***It is a compile-time error if the superclass or superinterface type of the anonymous class, T, or any subexpression of T, has one of the following forms:
    - A type variable (4.4) that was not declared as a type parameter (such as a type variable produced by capture conversion (5.1.10))
    - An intersection type (4.9)
    - A class or interface type, where the class or interface declaration is not accessible from the class or interface in which the expression appears.***
    The term "subexpression" includes type arguments of parameterized types (4.5), bounds of wildcards (4.5.1), and element types of array types (10.1). It excludes bounds of type variables.*** 

The reason for this is that anonymous class super type, which is parameterized, has a type argument (subexpression) being a type variable which was not declared as a type parameter.

The fact that E is inferred as a type variable with the upper bound becomes more obvious if we decide to override complexMethod:

        Foo t4 = new Foo<>() {
            public Foo<? extends B> complexMethod(B a){ return this; }
            //public Foo<B> complexMethod(B a){ return this; } ;//this causes compilation failure
        };

In this case providing return type as Foo<B> causes compilation failure. Only specifying the return type as Foo<? extends B> gets compilation to succeed.

In general the reasons why I think that E is inferred here as B<Y> are presented below (just meaningful steps are presented). Could you please tell if they are correct.

1. Initial bounds set created from type parameter bounds contains following items as per JLS 18.1.3:

    e :< B<e> (e - is inference variable);
    e :< Object (this is added because e had no proper upper bounds);

2. Then these bounds are processed by resolution process (JLS 18.4). During resolution e :< Object causes instantiation e=Object according to following assertion from JLS 18.4:

    Otherwise, where ai has proper upper bounds U1, ..., Uk, Ti = glb(U1, ..., Uk)

3. Incorporating e=Object causes following new constraint to be added Object :< B<Object> according to following assertion from JLS 18.3.1:   

    a = U and S <: T imply ���S[a:=U] <: T[a:=U]���

5. Constraint Object :< B<Object> reduces to false causing the second resolution attempt to take effect according to following assertion from JLS 18.4:

    Otherwise, the result contains the bound false, so a second attempt is made to instantiate { a1, ..., an } by performing the step below.

4. Fresh type variable Y with upper bound B<Y> is introduced according to assertions from JLS 18.4 presented below (Y upper bound is glb(Object,B<e>[e:=Y]) = B<e>[e:=Y] = B<Y>):

    then let Y1, ..., Yn be fresh type variables whose bounds are as follows:
    * For all i (1 ��� i ��� n), where ai has upper bounds U1, ..., Uk, let the upper bound of Yi be glb(U1 q, ..., Uk q), where q is the substitution [a1:=Y1, ..., an:=Yn].

5. Finally e is instantiated as a fresh type variable Y with the upper bound B<Y> according to the following assertion from JLS 18.4:

    Otherwise, for all i (1 ��� i ��� n), all bounds of the form G<..., ai, ...> = capture(G<...>) are removed from the current bound set, and the bounds a1 = Y1, ..., an = Yn are incorporated.

Thanks,
Georgiy.