constant references in enums
John Rose
john.r.rose at oracle.com
Fri Jan 22 20:12:19 UTC 2016
That all makes sense; it's consistent, although it makes me a little sad.
Enums should be able to define their own bit-fiddly constants and use
them to construct themselves, and the qualified expr is the way to do so.
I was confused about the status of the sugary expression "FOOE(FOOV)".
I guess it is a constructor invocation from a static initializer, but the spec
doesn't really categorize it, clearly enough to predict what should happen.
FTR, the use case comes from a Vector API POC:
> enum LaneType implements Impl.EnumWorkaround {
> ILLEGAL((byte)0,0), // sentinel for error reporting
> Z0(Z,0), Z1(Z,1), Z2(Z,2), Z4(Z,4), // zero-bit = void, one-bit, etc.
> // (signed,unsigned,float) x (2**{0,1,2,3,4)b)
> U1(U,1), U2(U,2), U4(U,4), U8(U,8), U16(U,16),
> S1(S,1), S2(S,2), S4(S,4), S8(S,8), S16(S,16),
> F1(F,1), F2(F,2), F4(F,4), F8(F,8), F16(F,16);
>
> /* JLS: "It is a compile-time error to reference a static field
> * of an enum type from constructors, instance initializers,
> * or instance variable initializer expressions of the enum
> * type, unless the field is a constant variable (4.12.4)."
> * So the following should work, but appears to be broken:
> */
> //private static final byte Z = 0x1, U = 0x2, S = 0x4, F = 0x08;
> private static final int BIT_SIZE_SHIFT = 4, BYTE_SIZE = 8;
>
> private int flags;
> LaneType(byte flags, int size) {
> int bitSize = (flags & Z) == 0 ? (size * BYTE_SIZE) : size;
> assert((flags & (-1 << BIT_SIZE_SHIFT)) == 0);
> this.flags = flags | (bitSize << BIT_SIZE_SHIFT);
> }
> public int bitSize() { return flags >> BIT_SIZE_SHIFT; }
> public int byteSize() { return bitSize() / BYTE_SIZE; }
> public boolean isUnsigned() { return (flags & U) != 0; }
> public boolean isSigned() { return (flags & S) != 0; }
> public boolean isFloat() { return (flags & F) != 0; }
> }
Ref: http://mail.openjdk.java.net/pipermail/panama-dev/2016-January/000288.html <http://cr.openjdk.java.net/~jrose/arrays/vector/VectorOp.java>
— John
On Jan 21, 2016, at 4:52 PM, Maurizio Cimadamore <maurizio.cimadamore at oracle.com> wrote:
>
> Compiler output for my last example:
>
> Main.java:48: error: illegal reference to static field from initializer
> int field1 = e;
> ^
> Main.java:52: error: illegal reference to static field from initializer
> int i1 = e;
> ^
> Main.java:57: error: illegal reference to static field from initializer
> int i1 = e;
> ^
> 3 errors
>
>
> As you can see, static reference from instance context is only allowed when the static is also a constant - as per 8.9.2.
>
> Maurizio
>
> On 22/01/16 00:51, Maurizio Cimadamore wrote:
>> My bad - the section you quote refers to a different scenario:
>>
>> enum Foo {
>> BAR;
>>
>> static int e = 0; //non constant
>> final static int ce = 42; //constant
>>
>> //8.9.2: It is a compile-time error to reference a static field of an enum type from...
>>
>> // instance variable initializer expression
>> int field1 = e;
>> int field2 = ce;
>>
>> // instance initializers
>> {
>> int i1 = e;
>> int i2 = ce;
>> }
>>
>> //constructors
>> Foo() {
>> int i1 = e;
>> int i2 = ce;
>> }
>> }
>>
>> So, in your case the access is occurring from another *static* variable initializer, so 8.9.2 does not apply. Which I think means that the same rules for ordinary classes apply - meaning that forward reference for statics is only allowed with fully qualified name. So it is consistent. And it is not a bug. Let's wait from some spec guru to chime in.
>>
>> Maurizio
>>
>> On 22/01/16 00:41, Maurizio Cimadamore wrote:
>>> If it helps - this is rejected too:
>>>
>>> class FooE {
>>> static FooE fe = new FooE(FOOC); // ?? error: illegal forward reference
>>> FooE(int k) {}
>>> public static final int FOOC = 42; // a constant variable
>>> }
>>>
>>> But - this isn't:
>>>
>>> class FooE {
>>> static FooE fe = new FooE(FooE.FOOC); // ?? error: illegal forward reference
>>> FooE(int k) {}
>>> public static final int FOOC = 42; // a constant variable
>>> // look, JLS 8.9.2 says "...unless the field is a constant variable"
>>> }
>>>
>>> And I know this is not a bug - i.e. the spec says that fully qualified names are allowed to forward references (see 8.3.3).
>>>
>>> So, I'm assuming that, since javac desugars away enums at parsing time (by translating them into classes similar to the one above), it ends up generating illegal code in your specific case. Or maybe the spec should be rectified to do something consistent in both cases.
>>>
>>> Btw - if you add 'FooE.' your examples compiles too :-)
>>>
>>> Maurizio
>>>
>>> On 22/01/16 00:16, John Rose wrote:
>>>> enum FooE {
>>>> FOOV(FOOC); // ?? error: illegal forward reference
>>>> FooE(int k) {}
>>>> public static final int FOOC = 42; // a constant variable
>>>> // look, JLS 8.9.2 says "...unless the field is a constant variable"
>>>> }
>>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.openjdk.java.net/pipermail/compiler-dev/attachments/20160122/7aaa7f99/attachment-0001.html>
More information about the compiler-dev
mailing list