Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8297122

Change IncompatibleClassChangeError to MatchException for exhaustive switch statements and switch expressions

XMLWordPrintable

    • Icon: CSR CSR
    • Resolution: Approved
    • Icon: P3 P3
    • 20
    • tools
    • None
    • low
    • Hide
      In a corpus run, 60 artifacts were found that (currently) have the generated IncompatibleClassChangeError in the context of switch expressions. It is not very likely the uses of these would be affected by a change of the IncompatibleClassChangeError to MatchException.
      Show
      In a corpus run, 60 artifacts were found that (currently) have the generated IncompatibleClassChangeError in the context of switch expressions. It is not very likely the uses of these would be affected by a change of the IncompatibleClassChangeError to MatchException.
    • Language construct
    • SE

      Summary

      Regulate the type of the exception emitted if no switch labels applies at runtime for both sealed hierarchies and enum classes. An exhaustive switch over an enum class (i.e. a switch expression, or a pattern switch statement) should throw MatchException rather than IncompatibleClassChangeError if no switch label applies at runtime.

      Problem

      When introducing switch expressions, we opted for a design where the switch body had to be exhaustive. When switching over an enum type, a switch body with case labels supporting all the enum constants for the enum type is considered exhaustive, meaning a default clause is not needed.

      However, there is a possibility that the enum class is changed after compilation of the switch expression, and a new enum constant added. Then when executing the switch expression, no label would apply.

      In JDK 14 it was decided that in this case, an IncompatibleClassChangeError should be thrown as that was a pre-existing exception that was generally understood by developers as a signal that things have got out of sync and re-compilation is needed.

      With the development of pattern matching enhanced switches, there are similar examples where a switch that has been determined to be exhaustive may, at runtime, find that case labels apply because of a change to a type hierarchy. For example, a switch over a sealed type: When switching over a sealed type, a switch body with case labels with type patterns matching all the permitted subclasses is considered exhaustive, meaning a default clause is not needed.

      If the sealed hierarchy has been changed after compilation of the switch, it is possible that when executing the switch that no label would apply. In this case we have settled on throwing a new exception MatchException.

      Unfortunately, currently we have a situation where a pattern switch could throw one of two possible exceptions depending on the type of the selector expression. In the future we plan on allowing switches with patterns that also contain enum constants. In this situation, it will be very difficult to define a runtime semantics that behaves in a predictable way. This will make many future enhancements confusing at best, or impossible at worst.

      Solution

      The solution is fairly straightforward: an exhaustive switch over an enum class (i.e. a switch expression, or a pattern switch statement) should throw MatchException rather than IncompatibleClassChangeError if no switch label applies at runtime.

      This changed behavior will currently only be selected when preview features are enabled with --enable-preview, as part of the pattern matching for switch feature. When the pattern matching for switch feature will be finalized, this behavior will become a standard behavior, but will only be used for up-to-date source level. I.e. behavior for older source levels will remain unchanged.

      This has been discussed in the expert group and has broad support: https://mail.openjdk.org/pipermail/amber-spec-experts/2022-November/003650.html

      Alternatives:

      1. Throw IncompatibleClassChangeError for all pattern matching failures. This feels like the wrong solution as firstly it could mean that pattern matching failures will be inadvertently caught by the wrong code. Moreover, IncompatibleClassChangeError has an accepted meaning to developers that doesn't match these erroneous cases.

      2. Make MatchException a subtype of IncompatibleClassChangeError. This will just add further confusion to developers.

      3. Keep the two exceptions and not develop the further enhancements to pattern matching. This would stop an important thread of future enhancements planned under Project Amber.

      Specification

      Attached is the revised JLS spec change document, and also a diff showing the changes to the spec to support these changes.

        1. ExceptionChange.patch
          3 kB
          Gavin Bierman

            jlahoda Jan Lahoda
            jlahoda Jan Lahoda
            Angelos Bimpoudis
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved: