Type parameters inside super() calls?

Maurizio Cimadamore maurizio.cimadamore at oracle.com
Thu Feb 2 00:31:34 UTC 2023


On 02/02/2023 00:13, Alex Buckley wrote:

> 8.1.3 has a nice note about intent:
>
>   "The purpose of a static context is to demarcate code that must not 
> refer explicitly or implicitly to the current instance of the class 
> whose declaration lexically encloses the static context. Consequently, 
> code that occurs in a static context is restricted in the following 
> ways: ..."
>
> Beyond that, I'm not sure what to say, because all of this has been in 
> place since Java 1.1.

I understand that this has been there since the beginning.

And, in a world where (a) there’s no generics and (b) you can’t have 
statements before super() - that para specifies the right behavior.

When you throw in type parameters, it seems to me that the “this is a 
static context” no longer works - as it cannot explain programs that are 
obviously valid (such as the one I have shown).

And, if we add statements before |super| it gets even worse, because now 
we can have types that are non-static, but that it’s not clear as to why 
such types couldn’t be referred to:

|class Foo { Foo() { class Local { String aString() { ... } } super(new 
Local().aString()); // is this legal? } } |

Now that we’re planning to do more work in this area [1], it would be 
IMHO a good time to see if the use of “static context” in 8.8.7.1 is 
really what we want.

Maurizio

[1] - https://bugs.openjdk.org/browse/JDK-8300786

>
> Alex
>
> On 2/1/2023 3:43 PM, Maurizio Cimadamore wrote:
>> While I agree that what javac does is against the JLS, is this a 
>> javac or a spec bug?
>>
>> I mean, consider this hierarchy:
>>
>> |class Sup<X> { Sup(X x) { ... } } class Sub<Y> extends Sup<Y> { 
>> Sub(Y y) { super(y); } } |
>>
>> What the rules are saying is that “y” in the Sub super call should be 
>> evaluated in a static context. But that doesn’t make any sense - 
>> because Y is not even a valid type in such a static context.
>>
>> And yet - this is a valid program. So, if typechecking “y” is 
>> correct, then, surely, typechecking “(Y)y” should also be correct? 
>> E.g. it seems to me that the use of “static context” here is an 
>> “approximation” for the behavior we really want (e.g. no access to 
>> instance fields, whether directly or indirectly).
>>
>> Maurizio
>>
>> On 01/02/2023 22:39, Alex Buckley wrote:
>>
>>> Your reading of the JLS is correct. The cast expression `(T)obj` 
>>> occurs in a static context, so the use of T should be disallowed, 
>>> and javac should reject the program.
>>>
>>> These rules in 8.8.7.1 and 8.1.3 are longstanding, and have not 
>>> changed recently, so I'm surprised that javac lets the program 
>>> through. That said, JLS16 saw a reworking of 8.1.3 (driven by 
>>> https://openjdk.org/jeps/395#Static-members-of-inner-classes) and 
>>> perhaps javac got a bit turned around over static contexts.
>>>
>>> As an additional test case, make the constructor generic -- `public 
>>> <U extends T> TypeParam ...` -- and cast obj to U rather than T -- 
>>> still illegal.
>>>
>>> Alex
>>>
>>> On 2/1/2023 12:45 PM, Archie Cobbs wrote:
>>>> This program compiles without error:
>>>>
>>>> import java.util.concurrent.atomic.*;
>>>> public class TypeParamStaticContext<T> extends AtomicReference<T> {
>>>>      public TypeParamStaticContext(Object obj) {
>>>>          super((T)obj);
>>>>      }
>>>> }
>>>>
>>>> Yet according to my reading of the JLS, the appearance of T inside 
>>>> the super() call should be disallowed:
>>>>
>>>> §8.8.7.1 <http://8.8.7.1>:
>>>>
>>>> An explicit constructor invocation statement introduces a static 
>>>> context (§8.1.3 
>>>> <https://docs.oracle.com/javase/specs/jls/se19/html/jls-8.html#jls-8.1.3>), 
>>>> which limits the use of constructs that refer to the current 
>>>> object. Notably, the keywords |this| and |super| are prohibited in 
>>>> a static context (§15.8.3 
>>>> <https://docs.oracle.com/javase/specs/jls/se19/html/jls-15.html#jls-15.8.3>, 
>>>> §15.11.2 
>>>> <https://docs.oracle.com/javase/specs/jls/se19/html/jls-15.html#jls-15.11.2>), 
>>>> as are unqualified references to instance variables, instance 
>>>> methods, and type parameters of lexically enclosing declarations 
>>>> (§6.5.5.1 
>>>> <https://docs.oracle.com/javase/specs/jls/se19/html/jls-6.html#jls-6.5.5.1>, 
>>>> §6.5.6.1 
>>>> <https://docs.oracle.com/javase/specs/jls/se19/html/jls-6.html#jls-6.5.6.1>, 
>>>> §15.12.3 
>>>> <https://docs.oracle.com/javase/specs/jls/se19/html/jls-15.html#jls-15.12.3>).
>>>>
>>>> §6.5.5.1 <http://6.5.5.1>:
>>>>
>>>> If a type name consists of a single /Identifier/, then the 
>>>> identifier must occur in the scope of exactly one declaration of a 
>>>> class, interface, or type parameter with this name (§6.3 
>>>> <https://docs.oracle.com/javase/specs/jls/se19/html/jls-6.html#jls-6.3>), 
>>>> or a compile-time error occurs.
>>>>
>>>> If the declaration denotes a type parameter of a generic class or 
>>>> interface C (§8.1.2 
>>>> <https://docs.oracle.com/javase/specs/jls/se19/html/jls-8.html#jls-8.1.2>, 
>>>> §9.1.2 
>>>> <https://docs.oracle.com/javase/specs/jls/se19/html/jls-9.html#jls-9.1.2>), 
>>>> then both of the following must be true, or a compile-time error 
>>>> occurs:
>>>>
>>>>   *
>>>>
>>>>     The type name does not occur in a static context (§8.1.3
>>>> <https://docs.oracle.com/javase/specs/jls/se19/html/jls-8.html#jls-8.1.3>) 
>>>>
>>>>
>>>>   *
>>>>
>>>>     If the type name appears in a nested class or interface 
>>>> declaration
>>>>     of C, then the immediately enclosing class or interface 
>>>> declaration
>>>>     of the type name is an inner class of C.
>>>>
>>>>
>>>> What am I missing?
>>>>
>>>> Thanks,
>>>> -Archie
>>>>
>>>> -- 
>>>> Archie L. Cobbs
>>
>>
​
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/compiler-dev/attachments/20230202/b8b7d405/attachment-0001.htm>


More information about the compiler-dev mailing list