Type parameters inside super() calls?

Alex Buckley alex.buckley at oracle.com
Thu Feb 2 01:04:44 UTC 2023


On 2/1/2023 4:31 PM, Maurizio Cimadamore wrote:> 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? } } |

To answer the question: the argument to `super(..)` is presently not 
legal because the `new Local()` part is presently not legal. (15.9.2: 
"If <<Local>> is an inner local class, then ... if the class instance 
creation expression occurs in a static context, then a compile-time 
error occurs.")

But you are saying this is "static context overreach", and that perhaps 
`new Local()` should be allowed there. Such an expression needs to use 
`this` as the immediately enclosing instance of the Local object, and 
that's fine as long as no-one can access the immediately enclosing 
instance ... but now we invoke a method on the Local object and ????

> 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.

I don't disagree.

Alex

> 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
>>>
>>>> 
>


More information about the compiler-dev mailing list