Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Enhanced Switch] ECJ tolerates fall through to default from a case with pattern label while javac rejects it. #3318

Open
srikanth-sankaran opened this issue Nov 15, 2024 · 6 comments
Assignees
Labels
javac ecj not compatible with javac

Comments

@srikanth-sankaran
Copy link
Contributor

srikanth-sankaran commented Nov 15, 2024

Found by code inspection:

This program is rejected by javac (illegal fall-through from a pattern) while ECJ compiles it:

public class X {	
	static /* @NonNull */ Object foo(/*@NonNull */ Object o) {
	    switch (o) {
	        case String s:
	        default:
	        	System.out.println();
	    }
	    return o;
	}
}  
@srikanth-sankaran srikanth-sankaran self-assigned this Nov 15, 2024
@iloveeclipse
Copy link
Member

From naive user point of view: why is this illegal? I mean not JLS but common sense. In the default case we don't assume some specific type, do we?

@srikanth-sankaran srikanth-sankaran changed the title [Enhanced Switch] ECJ tolerates illegal fall through to default from a case with pattern label [Enhanced Switch] ECJ tolerates fall through to default from a case with pattern label while javac rejects it. Nov 15, 2024
@srikanth-sankaran srikanth-sankaran added the javac ecj not compatible with javac label Nov 15, 2024
@srikanth-sankaran
Copy link
Contributor Author

From naive user point of view: why is this illegal? I mean not JLS but common sense. In the default case we don't assume some specific type, do we?

Good question.

This looks like a javac defect actually. To be confirmed by closer study and second opinion.

14.11.1 Switch Blocks:

...

It is a compile-time error if, in a switch block that consists of switch labeled
statement groups, a statement is labeled with a case label that declares one or more
pattern variables (§6.3.3), and either:
• An immediately preceding statement in the switch block can complete normally
(§14.22), or
• The statement is labeled with more than one switch label.

Operative phrase is a statement is labeled with a case label that declares one or more pattern variables - this is not true for default arm, so this should be OK.

On the other hand attempt to use the pattern binding from the prior case is clearly an error and is rejected:

public class X {	
	static /* @NonNull */ Object foo(/*@NonNull */ Object o) {
	    switch (o) {
	        case String s:
	        default:
	        	System.out.println(s);
	    }
	    return o;
	}
}  

elicits s cannot be resolved to a variable

Summary, this should be investigated as a difference vis a vis javac with likely blame on javac.

@srikanth-sankaran
Copy link
Contributor Author

Actually, upon re-reading, I feel this is a ECJ defect :) from a purely technical wording standpoint.

The statement System.out.println(); in the top/original submitted case is:

  • labeled with a case label that declares one or more pattern variables
  • labeled with more than one switch label.

So both boxes are ticked - ergo program is illegal.

To answer why it is illegal, you can reach the sysout through two arcs, one defining a pattern binding and one without. If it were legal, you won't know how you reached that place and so whether the pattern binding is definitely assigned or not. Attempting to use the pattern binding (which itself is disallowed correctly by ECJ but that is a separate matter) will result in indeterminate behavior.

@iloveeclipse
Copy link
Member

If it were legal, you won't know how you reached that place and so whether the pattern binding is definitely assigned or not

But if we don't use pattern binding we should be fine (from naive user point of view)?

@srikanth-sankaran
Copy link
Contributor Author

True. But that makes the pattern match binding variable initialization into redundant/dead code and that would be my take on why it is illegal.

If you instead used '_' as the binding variable it should be fine.

@srikanth-sankaran
Copy link
Contributor Author

True. But that makes the pattern match binding variable initialization into redundant/dead code and that would be my take on why it is illegal.

If you instead used '_' as the binding variable it should be fine.

For example, this compiles fine with both compilers:

public class X {	
	static  Object foo( Object o) {
	    switch (o) {
	        case String _ :
	        default :	
	        	System.out.println();
	    }
	    return o;
	}
}  

That said, javac also shows inconsistent behavior: This one compiles fine with javac from JDK23:

public class X {	
	static /* @NonNull */ Object foo(/*@NonNull */ Object o) {
	    switch (o) {
	        case String s:
	        	System.out.println();  // first println
	        default:
	        	System.out.println();
	    }
	    return o;
	}
}  

If you comment out the first println it will be rejected. But the presence or absence of that println statement doesn't alter the fall through status into the default case.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
javac ecj not compatible with javac
Projects
None yet
Development

No branches or pull requests

2 participants