JDK-8012039 : enum type variable not within its bound
  • Type: Bug
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 7
  • Priority: P4
  • Status: Open
  • Resolution: Unresolved
  • Submitted: 2013-04-04
  • Updated: 2015-12-11
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
tbd_majorUnresolved
Related Reports
Blocks :  
Relates :  
Relates :  
Relates :  
Description
FULL PRODUCT VERSION :
java version  " 1.7.0_07 " 
Java(TM) SE Runtime Environment (build 1.7.0_07-b11)
Java HotSpot(TM) 64-Bit Server VM (build 23.3-b01, mixed mode)

ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows [Version 6.1.7601]

A DESCRIPTION OF THE PROBLEM :
I have  " public interface MyInterface<T extends Enum<T> & OtherInterface> "  as the generic type of an interface, and one of the methods of the interface returns type T, which is obviously an enum. However, a separate static method that takes an enum as an argument will not recognize the returned type T as an enum.

See attached test case.

The attached test case fails to compile both in JDK 6 and JDK 7. It compiles fine in Eclipse 4.2.1.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
javac BugEnum.java

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The program should compile and produce the string  " success "  when run.
ACTUAL -
Java refuses to compile the class.

ERROR MESSAGES/STACK TRACES THAT OCCUR :
  BugEnum.java:24: error: method getSerializationName in class BugEnum cannot be applied to given types;
                System.out.println(getSerializationName(testMessage.getCommand()));
                                   ^
  required: E
  found: INT#1
  reason: inferred type does not conform to declared bound(s)
    inferred: INT#1
    bound(s): Enum<INT#1>
  where E is a type-variable:
    E extends Enum<E> declared in method <E>getSerializationName(E)
  where CAP#1 is a fresh type-variable:
    CAP#1 extends INT#1 from capture of ?
  where INT#1 is an intersection type:
    INT#1 extends Enum<CAP#1>,Command
1 error

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
/**Illustration of Java Enum-related compile bug.
*@author Garret Wilson
*/
public class BugEnum {

public interface Command {}

public interface CommandMessage<C extends Enum<C> & Command> {
public C getCommand();
}

public enum TestCommand implements Command {SUCCESS, FAILURE}

public static class TestCommandMessage implements CommandMessage<TestCommand> {
@Override public TestCommand getCommand() {return TestCommand.SUCCESS;}
}

public static <E extends Enum<E>> String getSerializationName(final E e) {
return e.name().toString().toLowerCase();
}

public static void main(String... args) {
CommandMessage<?> testMessage=new TestCommandMessage();
System.out.println(getSerializationName(testMessage.getCommand()));
}

}
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
This bug is hard to work around without removing the use of generics and/or having various (Object) casts and such.
Comments
The offending code, 'MethodResultInfo.U' in Resolve, can't be fully cleaned up until we have a better specification story for type variables with wildcard upper bounds. See JDK-7034922.
11-12-2015

This is caused by the fact that javac calls upper bound on the argument types ahead of the method check.
30-05-2013

Reduced test case: interface CommandMessage<C extends Enum<C>> { public C getCommand(); } class BugEnum { <E extends Enum<E>> void m(E e) { } void test(CommandMessage<?> c) { m(c.getCommand()); } }
11-04-2013

This is a known issue. It is caused by a 'trick' done by the javac compiler in order to get rid of captured type-variables; the argument types are reduced to their upper bounds before evaluating method calls. While this can lead to simplification certain times, it leads to inconsistencies in situation like these. Since Eclipse does not do the same trick, this particular program works well with Eclipse, but other programs will fail to compile. This program is rejected by all javac version since JDK 5, so it's not a JDK 7-only issue. We are considering making compiler compliant to the spec in this very area in JDK 8, but only if program is compiled with -source 8. For compatibility reasons it would be impractical to remove the code that is causing the problem in all releases, as there is code out there relying on it.
11-04-2013