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

Pattern matching in switch results in VerifyError after successful compilation

XMLWordPrintable

    • generic
    • generic

      ADDITIONAL SYSTEM INFORMATION :
      OS: Microsoft Windows 10 Pro 10.0.19045 build 19045
      Java version: OpenJDK 20.0.2 (Downloaded through Intellij Idea 2023.2)

      A DESCRIPTION OF THE PROBLEM :
      See source code below. The code compiles successfully, however running it gives `VerifyError`. The error disappears when:
      - either branch is removed
      - when using different variables:
      ```
      // fine
      -> throw new UnsupportedOperationException("some error");
      -> throw new UnsupportedOperationException("another error");

      // fine
      -> throw new UnsupportedOperationException(e.toString());
      -> throw new UnsupportedOperationException(e.toString());

      // fine
      -> throw new UnsupportedOperationException(v.toString());
      -> throw new UnsupportedOperationException(e.toString());

      // not fine
      -> throw new UnsupportedOperationException(e.toString());
      -> throw new UnsupportedOperationException(v.toString());

      // not fine
      -> throw new UnsupportedOperationException(v.toString());
      -> throw new UnsupportedOperationException(v.toString());
      ```
      The error persists even if:
      - the branches use different variable names (`v1`, `v2`, `e1` and `e2` for example)
      - guards are used (`v.value() == 1` for example)
      - `var` is replaced with the actual type

      REGRESSION : Last worked in version 19

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Compile with: `javac --enable-preview --source 20 ./Test.java`
      Run with: `java --enable-preview --source 20 Test`
      Or with just the `java` tool: `java --enable-preview --source 20 Test.java`

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      Code runs without errors
      ACTUAL -
      Exception in thread "main" java.lang.VerifyError: Bad local variable type
      Exception Details:
        Location:
          random/Test.eval(Lrandom/Test$Expr;)I @178: aload
        Reason:
          Type top (current frame, locals[7]) is not assignable to reference type
        Current Frame:
          bci: @178
          flags: { }
          locals: { 'random/Test$Expr', 'random/Test$Expr', integer, 'random/Test$Plus', top, top, 'random/Test$Expr', top, 'random/Test$Expr', integer }
          stack: { uninitialized 174, uninitialized 174 }
        Bytecode:
          0000000: 2a59 b800 1757 4c03 3d2b 1cba 001d 0000
          0000010: ab00 0000 0000 00b0 0000 0001 0000 0000
          0000020: 0000 0014 2bc0 0007 4e2d b600 213a 0803
          0000030: 3609 1908 1509 ba00 2500 00aa 0000 0080
          0000040: ffff ffff 0000 0001 0000 0046 0000 0019
          0000050: 0000 0046 1908 c000 093a 042d b600 263a
          0000060: 0a19 0a3a 0519 04b6 0029 049f 0009 0436
          0000070: 09a7 ffc1 bb00 2d59 1904 b600 2fb7 0033
          0000080: bf19 083a 0619 06c6 0027 2db6 0026 3a0a
          0000090: 190a c100 0999 0013 190a c000 093a 0719
          00000a0: 07b6 0029 049f 0009 0536 09a7 ff87 bb00
          00000b0: 2d59 1907 b600 2fb7 0033 bf04 3da7 ff4c
          00000c0: 03a7 0003 ac4c bb00 3859 2bb6 003a 2bb7
          00000d0: 003b bf
        Exception Handler Table:
          bci [42, 45] => handler: 197
          bci [92, 95] => handler: 197
          bci [139, 142] => handler: 197
        Stackmap Table:
          append_frame(@9,Object[#67],Integer)
          same_frame(@36)
          full_frame(@50,{Object[#67],Object[#67],Integer,Object[#7],Top,Top,Top,Top,Object[#67],Integer},{})
          same_frame(@84)
          full_frame(@116,{Object[#67],Object[#67],Integer,Object[#7],Object[#9],Object[#67],Top,Top,Object[#67],Integer},{})
          full_frame(@129,{Object[#67],Object[#67],Integer,Object[#7],Top,Top,Top,Top,Object[#67],Integer},{})
          full_frame(@168,{Object[#67],Object[#67],Integer,Object[#7],Top,Top,Object[#67],Top,Object[#67],Integer},{})
          same_frame(@174)
          full_frame(@187,{Object[#67],Object[#67],Integer,Object[#7],Top,Top,Top,Top,Object[#67],Integer},{})
          full_frame(@192,{Object[#67],Object[#67],Integer},{})
          full_frame(@196,{Object[#67]},{Integer})
          same_locals_1_stack_item_frame(@197,Object[#54])

              at java.base/java.lang.Class.forName0(Native Method)
              at java.base/java.lang.Class.forName(Class.java:496)
              at java.base/java.lang.Class.forName(Class.java:475)
              at jdk.compiler/com.sun.tools.javac.launcher.Main.execute(Main.java:425)
              at jdk.compiler/com.sun.tools.javac.launcher.Main.run(Main.java:205)
              at jdk.compiler/com.sun.tools.javac.launcher.Main.main(Main.java:132)

      ---------- BEGIN SOURCE ----------
      public class Test {
          public static void main(String[] args) {
              eval(new Plus(new Value(1), new Value(2)));
          }

          private static int eval(Expr expr) {
              return switch (expr) {
                  case Plus(Value v, var e) -> throw new UnsupportedOperationException(v.toString());
                  case Plus(var e, Value v) -> throw new UnsupportedOperationException(v.toString());
                  default -> 0;
              };
          }

          private sealed interface Expr permits Value, Plus {}
          private record Value(int value) implements Expr {}
          private record Plus(Expr left, Expr right) implements Expr {}
      }
      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      Using if-else chain with `instanceof` works as expected

      FREQUENCY : always


            Unassigned Unassigned
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated:
              Resolved: