eclipse-jdt / eclipse.jdt.core

Eclipse Public License 2.0
165 stars 130 forks source link

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

Open srikanth-sankaran opened 3 hours ago

srikanth-sankaran commented 3 hours ago

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;
    }
}  
iloveeclipse commented 2 hours ago

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 commented 2 hours ago

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 commented 2 hours ago

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:

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 commented 2 hours ago

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 commented 25 minutes ago

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.