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

Exception when compiling switch expression with inferred type

XMLWordPrintable

    • master
    • generic
    • generic

      ADDITIONAL SYSTEM INFORMATION :
      javac 21.0.7

      openjdk version "21.0.7" 2025-04-15 LTS
      OpenJDK Runtime Environment Temurin-21.0.7+6 (build 21.0.7+6-LTS)
      OpenJDK 64-Bit Server VM Temurin-21.0.7+6 (build 21.0.7+6-LTS, mixed mode, sharing)

      Linux 6.8.0-59-generic #61-Ubuntu SMP PREEMPT_DYNAMIC Fri Apr 11 23:16:11 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux

      A DESCRIPTION OF THE PROBLEM :
      Given the following support classes:
      ```
      abstract class Reader {}
      interface Readable<R extends Reader> {
          R getReader();
      }
      ```

      javac fails to compile the following code making use of a switch expression and a type pattern case:
      ```
      void test(Object obj) {
          var reader = switch (obj) {
              case Readable<?> readable -> readable.getReader();
              default -> null;
          };

          // ...
      }
      ```

      With the following error:
      test.java:10: error: <captured wildcard> is not public in null; cannot be accessed from outside package
                  case Readable<?> readable -> readable.getReader();

      The type of the source object `obj` seems irrelevant (except if it is Readable<?> but that's to be expected).

      Interestingly, the following has no issues compiling:
      ```
      void test(Object obj) {
          var reader = switch (obj) {
              case Readable<?> readable -> readable.getReader();
              default -> (Reader) null;
          };
      }
      ```

      It also has no issues compiling if any other case returning an unrelated type is present (where in which case the var is resolved to Object), replacing the null in default case with a non-null value (e.g. new Object()) also works.

      The type inference also works if the case rule uses the rawtype Readable, where the resulting reader variable is emitted as Reader type in the class file.

      Returning any instance of Reader in the default case also fixes the issue, although semantically different from what we are trying to achieve.

      From a rough analysis of the source of the error message, it seems like the compiler attempts to compare the type given by the default case and the generic case to infer the var type, failing to compare the captured wildcard against the untyped null symbol. This issue is not reproducible when the reader variable is explicitly typed to `Reader` (with or without typing the null in the default branch).


      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      - given the provided test file in Test.java
      - javac Test.java

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      The successful compilation of the file
      ACTUAL -
      > javac Test.java
      Test.java:15: error: <captured wildcard> is not public in null; cannot be accessed from outside package
                  case Readable<?> readable -> readable.getReader();
                                                                 ^
      1 error

      Note: the message targets colon 60, so the lparen of the getReader function call.

      ---------- BEGIN SOURCE ----------
      abstract class Reader {
      }

      interface Readable<R extends Reader> {
          R getReader();
      }

      public class Test {

          public static void main(String[] args) {}

          void test(Object obj) {
              var reader = switch (obj) {
                  case Readable<?> readable -> readable.getReader();
                  default -> null;
              };
          }
      }

      ---------- END SOURCE ----------

            jlahoda Jan Lahoda
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            4 Start watching this issue

              Created:
              Updated:
              Resolved: