eclipse-jdt / eclipse.jdt.core

Eclipse Public License 2.0
156 stars 123 forks source link

Switch pattern matching accepts invalid case #2722

Closed nlisker closed 1 month ago

nlisker commented 1 month ago
class Test {

    interface Inter {}

    class Cls {}

    void test(Inter inter) {
        switch (inter) {
            case Cls s -> {}
            default -> {}
        };
    }
}

The case for Cls should be rejected as it can't be a match for Inter, however, the compiler throws no error. Making the interface sealed (and adding a subtype) doesn't make a difference.

Version: 2024-06 (4.32) Build id: I20240601-0610

srikanth-sankaran commented 1 month ago

Did you check the behavior with javac ? It also compiles the program above. I don't see why there should be an error. While Cls doesn't implement I, a subclass of Cls may ?

For the case where Making the interface sealed (and adding a subtype) doesn't make a difference. please provide a test case. That will eliminate guess work.

ATM I don't see a defect here

srikanth-sankaran commented 1 month ago

I recommend always testing against javac.

srikanth-sankaran commented 1 month ago

In the parlance of JLS, Cls is not disjoint from Inter. In the following case where Cls has been declared final, Cls is indeed disjoint from Inter and ECJ issues an error correctly: Type mismatch: cannot convert from Test.Inter to Test.Cls

class Test {

    interface Inter {}

    final class Cls {}

    void test(Inter inter) {
        switch (inter) {
            case Cls s -> {}
            default -> {}
        };
    }
}
srikanth-sankaran commented 1 month ago

Making the interface sealed (and adding a subtype) doesn't make a difference.

ECJ and javac both reject this:

class Test {

    sealed interface Inter permits Klass {}

    final class Klass implements Inter {}

    class Cls {}

    void test(Inter inter) {
        switch (inter) {
            case Cls s -> {}
            default -> {}
        };
    }
}

I plan to close this with no change, unless you are able to produce a test case that shows ECJ differing from the spec or the reference compiler i.e, javac

nlisker commented 1 month ago

Making the interface sealed (and adding a subtype) doesn't make a difference.

ECJ and javac both reject this:

class Test {

  sealed interface Inter permits Klass {}

  final class Klass implements Inter {}

  class Cls {}

  void test(Inter inter) {
      switch (inter) {
          case Cls s -> {}
          default -> {}
      };
  }
}

javac rejects this, but ECJ accepts this for me with 2024-06 (4.32) and Java 22. Here is a screenshot: image

Compare with making Cls final, where I get the same error as you: image

Perhaps it was fixed after 4.32?

srikanth-sankaran commented 1 month ago

I'll check - there have been many fixes in this area in the past month.

nlisker commented 1 month ago

I tested with the latest integration build: Version: 2024-09 (4.33) Build id: I20240717-1800

The problem is fixed there - ECJ rejects the code.

srikanth-sankaran commented 1 month ago

By git history time travel, I could determine that this was fixed via https://github.com/eclipse-jdt/eclipse.jdt.core/issues/2595

srikanth-sankaran commented 1 month ago

duplicate of https://github.com/eclipse-jdt/eclipse.jdt.core/issues/2595