Bug 541604 - Java problem: "Cannot cast from Enum<Enum<E>>" although it should be
Summary: Java problem: "Cannot cast from Enum<Enum<E>>" although it should be
Status: NEW
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 4.9   Edit
Hardware: PC Linux
: P3 normal (vote)
Target Milestone: ---   Edit
Assignee: JDT-Core-Inbox CLA
QA Contact:
URL:
Whiteboard: stalebug
Keywords:
Depends on:
Blocks:
 
Reported: 2018-11-27 09:48 EST by Tom K CLA
Modified: 2022-11-13 19:33 EST (History)
1 user (show)

See Also:


Attachments
reproducer (20.00 KB, application/x-tar)
2018-11-27 09:48 EST, Tom K CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Tom K CLA 2018-11-27 09:48:57 EST
Created attachment 276724 [details]
reproducer

See example attached. Eclipse shows an error, but the javac compiler on the command line (openjdk) and other ides are fine.

"The direct superclass of an enum type E is Enum<E>."
https://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.1.4

So the direct superclass of TestEnum is Enum<TestEnum>. Thus it should infer the generic parameter from the cast type to E=TestEnum and then should be compatible. 

Note that the example works if passing the type param manually:

TestEnum e = (TestEnum)ret.<TestEnum>getValue();

So it seems to be an issue with type inference from cast?

Preview:


public class Main {

	public enum TestEnum {
		ONE;
	}
	
	public static class RetEnum {
		
		public <E extends Enum<E>> E getValue() {
			return (E)TestEnum.ONE;
		}
		
	}
	
	public static void main(String[] args) {
		RetEnum ret = new RetEnum();
		TestEnum e = (TestEnum)ret.getValue();
	}

}

Context: Java 8 and OpenJDK
Comment 1 Stephan Herrmann CLA 2018-11-27 11:21:15 EST
I can reproduce all the back from 3.2.2 (interestingly 3.1.2 did accept the program with a bunch of warnings).


The key question here is: how is inference of ret.getValue() performed?

Firstly, it occurs in a casting context, which is distinct from assignment or invocation contexts, hence the invocation is a standalone expression, not a poly expression.

This means that ยง18.5.2.1. does not apply and AFAICS no target type is considered during inference.
I'd have to check what E is infered to without a target type, but most likely the resulting Enum<X> is indeed not castable to TestEnum (I guess X is some unspeakable type variable).

Perhaps javac still thinks that the invocation is a poly expression? But then using the cast type as a target type seems strange to me: if we assume that the cast is necessary, then inference with this type as the target type should actually fail.

In fact, the alternative idiom is better Java: it allows the compiler to do the type checking rather than deferring it to a runtime check:
  
        TestEnum e = ret.<TestEnum>getValue();

Hence it seems we have three options:
(1) advise users to write type-safer code, or
(2) invent some rule on top of JLS to "improve" type inference.
(3) invest more investigation to check if Enum<X> is by some rule compatible
    to TestEnum (for "normal" types X it clearly is not).

I'm leaning towards (1).
Comment 2 Tom K CLA 2018-11-27 11:52:27 EST
Of course (1) would be better, but in practice you will see this situation.

And it is IMO not acceptable that Eclipse shows a Java error where the openjdk / oracle compiler does not.

We ran into this internally working with multiple IDEs and it is more than a nuisance if the code compiles on one setup and shows IDE errors for other users that check out that same code.
Comment 3 Stephan Herrmann CLA 2018-11-27 12:13:39 EST
(In reply to Tom K from comment #2)
> And it is IMO not acceptable that Eclipse shows a Java error where the
> openjdk / oracle compiler does not.

Sorry, but JLS, not javac is the boss.

We simply don't yet know, which of the compilers has a bug and must be fixed
(I only have a vague idea how javac _could_ be wrong here, but I could be wrong).
 
> We ran into this internally working with multiple IDEs and it is more than a
> nuisance if the code compiles on one setup and shows IDE errors for other
> users that check out that same code.

I can assure you, that if we just "fix" this issue without a clear understanding how the fix relates to JLS, the change will cause breakage in totally unexpected situations.

This is a tough and highly complex business. Without breaking the example down to precise language rules it is impossible to make progress.

As you already had a look into JLS, maybe you want to help and figure out which rules in JLS would tell us to accept the program? If so, I could help by telling (from the debugger) which infered type ecj uses during type checking.
Comment 4 Eclipse Genie CLA 2020-11-17 13:35:45 EST
This bug hasn't had any activity in quite some time. Maybe the problem got resolved, was a duplicate of something else, or became less pressing for some reason - or maybe it's still relevant but just hasn't been looked at yet.

If you have further information on the current state of the bug, please add it. The information can be, for example, that the problem still occurs, that you still want the feature, that more information is needed, or that the bug is (for whatever reason) no longer relevant.

--
The automated Eclipse Genie.
Comment 5 Eclipse Genie CLA 2022-11-13 19:33:01 EST
This bug hasn't had any activity in quite some time. Maybe the problem got resolved, was a duplicate of something else, or became less pressing for some reason - or maybe it's still relevant but just hasn't been looked at yet.

If you have further information on the current state of the bug, please add it. The information can be, for example, that the problem still occurs, that you still want the feature, that more information is needed, or that the bug is (for whatever reason) no longer relevant.

--
The automated Eclipse Genie.