United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
Bug ID: JDK-6209839 Illegal forward reference to enum constants allowed by javac
JDK-6209839 : Illegal forward reference to enum constants allowed by javac

Details
Type:
Bug
Submit Date:
2004-12-17
Status:
Closed
Updated Date:
2010-04-02
Project Name:
JDK
Resolved Date:
2005-12-17
Component:
tools
OS:
windows_xp
Sub-Component:
javac
CPU:
x86
Priority:
P3
Resolution:
Fixed
Affected Versions:
5.0
Fixed Versions:

Related Reports
Relates:

Sub Tasks

Description
FULL PRODUCT VERSION :
java version "1.5.0"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0-b64)
Java HotSpot(TM) Client VM (build 1.5.0-b64, mixed mode)

ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows XP [Version 5.1.2600]

A DESCRIPTION OF THE PROBLEM :
Consider the code below:

    public enum EnumTest {

        anEnumValue {
            private final EnumTest thisOne = anEnumValue;

            String getMessage() { return "Here is what thisOne gets assigned: " + thisOne; }
        };

        abstract String getMessage();

        public static void main(String[] args) {
            System.out.println(anEnumValue.getMessage());
        }

    }

This code compiles, but when you run it, you get the output:
    Here is what thisOne gets assigned: null
  
What this means is that the final local variable thisOne defined as a constant-specific field inside the enum constant anEnumValue has been assigned null.

This is NOT the behavior that I would have expected: I would have thought that it would really pick up the non-null reference to anEnumValue, especially given that it compiles.

But if the semantics of enums in java do not support this behavior, then at least javac should fail with the error that this is an illegal forward reference, rather than compile and allow it to fail at runtime.


STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the code above.


REPRODUCIBILITY :
This bug can be reproduced always.

CUSTOMER SUBMITTED WORKAROUND :
NONE, and I would really like to code using the technique illustrated above, as it is a great way to program state machines, which is something that enums really should be used for.
###@###.### 2004-12-17 00:39:14 GMT

                                    

Comments
EVALUATION

It is impossible to generate code for the most general instances of this
problem.  The global static variable holding the reference to anEnumValue
is not initialized before the object is constructed.  This means that you
cannot refer to anEnumValue during it's construction.

However, the compiler fails to report this problem.

Conclusion: the program can't be expected to work and might even be illegal.

###@###.### 2004-12-17 02:37:35 GMT

This is a specification violation as the JLS states the following:

"It is a compile-time error to reference a static field of an enum type
that is not a compile-time constant (15.28) from constructors, instance
initializer blocks, or instance variable initializer expressions of that
type.  It is a compile-time error for the constructors, instance initializer
blocks, or instance variable initializer expressions of an enum constant e1
to refer to itself or an enum constant of the same type that is declared to
the right of e1."

###@###.### 2005-1-20 23:39:26 GMT

In response to recent SDN comment:

See page 252 of the JLS.

###@###.### 2005-07-02 18:35:46 GMT
                                     
2004-12-17
WORK AROUND

The trivial work around is to use this.  However that will not work for more
general cases.  Consider an approach like this:

public enum EnumTest {
    anotherEnumConstant,

    anEnumValue(anotherEnumConstant) {
	String getMessage() { return "Here is what thisOne gets assigned: " + thisOne; }
    };

    protected final EnumTest thisOne;

    EnumTest(EnumTest other) {
	thisOne = other;
    }

    EnumTest() {
	thisOne = null;
    }


    String getMessage() { return null; }

    public static void main(String[] args) {
	System.out.println(anEnumValue.getMessage());
    }

}

###@###.### 2004-12-17 02:37:35 GMT
                                     
2004-12-17
SUGGESTED FIX

Index: src/share/classes/com/sun/tools/javac/comp/Attr.java
===========================================================
@@ -2044,13 +2044,21 @@
 
 	    // In an enum type, constructors and instance initializers
 	    // may not reference its static members unless they are constant.
-	    if (((v.flags() & STATIC) != 0) &&
-		((v.owner.flags() & ENUM) != 0) &&
-                v.constValue == null &&
-		v.owner == env.info.scope.owner.enclClass() &&
-		Resolve.isInitializer(env))
+	    checkEnumInitializer: {
+		if ((v.flags() & STATIC) == 0)
+		    break checkEnumInitializer;
+		if ((v.owner.flags() & ENUM) == 0)
+		    break checkEnumInitializer;
+		if (v.constValue != null)
+		    break checkEnumInitializer;
+		ClassSymbol enclClass = env.info.scope.owner.enclClass();
+		if (v.owner != enclClass && v.owner != enclClass.owner.enclClass())
+		    break checkEnumInitializer;
+		if (!Resolve.isInitializer(env))
+		    break checkEnumInitializer;
 		log.error(tree.pos, "illegal.enum.static.ref");
 	}
+	}
 
         /** Can the given symbol be the owner of code which forms part
 	 *  if class initialization? This is the case if the symbol is

###@###.### 2005-05-31 05:23:48 GMT
                                     
2005-05-31



Hardware and Software, Engineered to Work Together