Anonymous class creation and diamonds: bound 'E extends B<E>'

Dan Smith daniel.smith at oracle.com
Fri Apr 24 19:34:18 UTC 2015


Georgiy asked me to take a look at this.  FWIW, I agree: this is the kind of thing that the check is supposed to prevent (and, downstream, I wonder what Signature attribute we end up with, since we can't express 'B<Y>'.

—Dan

> On Apr 22, 2015, at 11:32 AM, Maurizio Cimadamore <maurizio.cimadamore at oracle.com> wrote:
> 
> I believe you are correct - and I believe the issue is that the fresh variable generated by javac is internally a TypeVar object, rather than a CapturedType object - meaning that it will fool the denotable check (which looks for CapturedTypes).
> 
> @Srikanth - can you look into this?
> 
> @Georgiy - good catch! Many thanks!
> 
> Maurizio
> 
> On 22/04/15 17:37, Georgiy Rakov wrote:
>> Hello,
>> 
>> 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 <https://bugs.openjdk.java.net/browse/JDK-8073593?focusedCommentId=13622110&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-13622110>:
>> ***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.
> 

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.openjdk.java.net/pipermail/compiler-dev/attachments/20150424/66c4aa0d/attachment.html>


More information about the compiler-dev mailing list