[enhanced-enums]: Enhanced enums failure with raw types?

B. Blaser bsrbnd at gmail.com
Mon Sep 11 19:25:46 UTC 2017


On 11 September 2017 at 15:27, Maurizio Cimadamore
<maurizio.cimadamore at oracle.com> wrote:
> Yep - it's a bug in the impl - in the sense that the members of a raw types
> are erased, meaning that the constructor of E, viewed as a member of a raw
> type is simply:
>
> E(Class clazz)
>
> So, your code should work (with warning).
>
> That said, I don't think fixing this is a priority, (as anticipated) given
> the current status of the feature.

I'd like to take back the main reason you gave in "enhanced enums -
end of the road?" to put this JEP in standby:

"there's no way to write down the type of an enum set which contains
heterogeneous options - the wildcard path doesn't help either"

So, neither "EnumSet<Option>", nor "EnumSet<Option<?>>" could work, as
you explained.

But I think "EnumSet<Option<Object>>" might help representing
heterogeneous options in some situations, for example:

public class A {
    enum G<X> {
        INTEGER<Integer>(Integer.class);
        G(Class<X> clazz) {}
    }

    public static void main(String... args) {
//        EnumSet<G> g1 = EnumSet.allOf(G.class);
//        EnumSet<G<?>> g2 = EnumSet.allOf(G.class);
        EnumSet<G<Object>> g3 = EnumSet.allOf(G.class);
    }
}

Here, "g1" and "g2" would fail as you explained but g3 would succeed.

I don't know if this could rehabilitate enhanced enums but I've just
tried to understand the blocking reason.

What do you think of this way of representing heterogeneous options?

Bernard

> Maurizio
>
>
>
> On 11/09/17 12:38, B. Blaser wrote:
>>
>> Hi,
>>
>> On 11 September 2017 at 10:35, Maurizio Cimadamore
>> <maurizio.cimadamore at oracle.com> wrote:
>>>
>>> Thanks B.
>>> unfortunately, the enhanced enum feature is not gonna make it, because of
>>> serious issues discovered during the exploration phase - see this email:
>>>
>>>
>>> http://mail.openjdk.java.net/pipermail/amber-spec-experts/2017-May/000041.html
>>>
>>> That said, I can't find 'raw type in an enhanced enum' in your example -
>>> is
>>> this the right source? You mean 'F' - which is not raw - just
>>> unparameterized?
>>
>> The problem is in "E" ("F" and "C" are working fine, they are just
>> here as comparison):
>>
>> public class A {
>>      enum E<X> {
>>          INTEGER(Integer.class);
>>          E(Class<X> clazz) {}
>>      }
>> }
>>
>> This simple example doesn't compile because the current version of
>> javac determines "E<X>" as type for "INTEGER" and is then expecting
>> "Class<X>" as argument to the constructor which is incompatible with
>> "Class<Integer>" (INTEGER<Integer> would work fine).
>>
>> So, I think the type of INTEGER (in our example) should be "E", the
>> erasure of "E<X>", and the expected argument would be "Class" which is
>> compatible with "Class<Integer>" (but producing an unchecked warning).
>>
>> We could simulate this with classes, as follows:
>>
>> public class A {
>>      static class C<X> {
>>          C INTEGER = new C(Integer.class);
>>          C(Class<X> clazz) {}
>>      }
>> }
>>
>> I think this is only a small compiler bug (see the patch below), not a
>> problem of specification.
>> The fix simply ensures that "INTEGER" (without type argument in the
>> parameterized enum "E<X>") will have type "E" and not "E<X>" which
>> wouldn't make any sense at my opinion.
>>
>> Note that the output of "javac -Xlint:unchecked A.java" I gave
>> yesterday is what I would expect (and it's produced with the fix I
>> suggested).
>> The actual version simply fails to compile this example ending with an
>> error as explained above.
>>
>> I hope this is clearer...
>> What do you think?
>>
>> Cheers,
>> Bernard
>>
>>> Cheers
>>> Maurizio
>>>
>>>
>>>
>>> On 10/09/17 18:20, B. Blaser wrote:
>>>>
>>>> Vicente, Maurizio, All,
>>>>
>>>> Consider the following example involving a raw type in an enhanced enum:
>>>>
>>>> public class A {
>>>>       enum E<X> {
>>>>           INTEGER(Integer.class), FLOAT<Float>(Float.class);
>>>>           E(Class<X> clazz) {}
>>>>       }
>>>>
>>>>       enum F {
>>>>           INTEGER(Integer.class);
>>>>           F(Class<?> clazz) {}
>>>>       }
>>>>
>>>>       static class C<X> {
>>>>           C INTEGER = new C(Integer.class), FLOAT = new
>>>> C<Float>(Float.class);
>>>>           C(Class<X> clazz) {}
>>>>       }
>>>> }
>>>>
>>>> Javac fails to compile the latter but I'd be more expecting an
>>>> unchecked warning instead, as for classes:
>>>>
>>>> $ javac -Xlint:unchecked A.java
>>>> A.java:3: warning: [unchecked] unchecked call to E(Class<X>) as a
>>>> member of the raw type E
>>>>           INTEGER(Integer.class), FLOAT<Float>(Float.class);
>>>>                  ^
>>>>     where X is a type-variable:
>>>>       X extends Object declared in enum E
>>>> A.java:13: warning: [unchecked] unchecked call to C(Class<X>) as a
>>>> member of the raw type C
>>>>           C INTEGER = new C(Integer.class), FLOAT = new
>>>> C<Float>(Float.class);
>>>>                       ^
>>>>     where X is a type-variable:
>>>>       X extends Object declared in class C
>>>> 2 warnings
>>>>
>>>> I've provided a simple fix here under (repo.: amber, branch:
>>>> enhanced-enums, rev.: 7a22956a0562).
>>>>
>>>> Any comment is welcome,
>>>> Bernard
>>>>
>>>> diff -r 7a22956a0562
>>>> src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java
>>>> --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java
>>>>      Fri Sep 08 00:00:41 2017 +0200
>>>> +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java
>>>>      Sun Sep 10 16:23:02 2017 +0200
>>>> @@ -903,15 +903,19 @@
>>>>        }
>>>>
>>>>        Type attribExprAsEnumType(Env<AttrContext> env, JCExpression
>>>> type) {
>>>> +        return attribExprAsEnumType(env, type, true);
>>>> +    }
>>>> +    Type attribExprAsEnumType(Env<AttrContext> env, JCExpression
>>>> type, boolean erase) {
>>>>            if (type.hasTag(IDENT)) {
>>>>                JCIdent id = (JCIdent)type;
>>>>                Assert.check((env.enclClass.sym.flags() & ENUM) != 0);
>>>> -            id.type = env.info.scope.owner.enclClass().type;
>>>> +            Type t = env.info.scope.owner.enclClass().type;
>>>> +            id.type = t.isParameterized() && erase ? types.erasure(t):
>>>> t;
>>>>                id.sym = env.info.scope.owner.enclClass();
>>>>                return id.type;
>>>>            } else {
>>>>                JCTypeApply ta = (JCTypeApply)type;
>>>> -            Type enumBaseType = attribExprAsEnumType(env, ta.clazz);
>>>> +            Type enumBaseType = attribExprAsEnumType(env, ta.clazz,
>>>> false);
>>>>                ResultInfo prevInfo = resultInfo;
>>>>                resultInfo = unknownTypeInfo;
>>>>                try {
>>>
>>>
>


More information about the amber-dev mailing list