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

VerifyError with JEP 405 pattern match

    XMLWordPrintable

Details

    • b29
    • generic
    • generic

    Backports

      Description

        ADDITIONAL SYSTEM INFORMATION :
        Ubuntu 20.04
        OpenJDK Runtime Environment (build 19-ea+25-1892)

        A DESCRIPTION OF THE PROBLEM :
        A method that uses instanceof pattern matching for records fails with a verify error. Rewriting it with classic instanceof succeeds.

        STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
        Run the program below with Java 19.

        EXPECTED VERSUS ACTUAL BEHAVIOR :
        EXPECTED -
        The program runs and prints 3660.0 s
        ACTUAL -
        Error: Unable to initialize main class Test3
        Caused by: java.lang.VerifyError: Bad return type
        Exception Details:
          Location:
            Test3.$proxy$unit(LLength;)LLengthUnit; @4: areturn
          Reason:
            Type 'QuantityUnit' (current frame, stack[0]) is not assignable to 'LengthUnit' (from method signature)
          Current Frame:
            bci: @4
            flags: { }
            locals: { 'Length' }
            stack: { 'QuantityUnit' }
          Bytecode:
            0000000: 2ab6 001a b04c bb00 0959 2bb6 000b 2bb7
            0000010: 000f bf
          Exception Handler Table:
            bci [0, 4] => handler: 5
          Stackmap Table:
            same_locals_1_stack_item_frame(@5,Object[#7])

        ---------- BEGIN SOURCE ----------
        interface QuantityUnit {
           double factor();
        }

        enum LengthUnit implements QuantityUnit {
           m(1), cm(0.01), in(0.01 / 2.54);

           private final double factor;

           public double factor() {
              return factor;
           }
           LengthUnit(double factor) {
              this.factor = factor;
           }

           public static final LengthUnit PREFERRED = m;
        }

        enum TimeUnit implements QuantityUnit {
           s(1), min(60), h(60 * 60);
           private final double factor;
           public double factor() {
              return factor;
           }
           TimeUnit(double factor) {
              this.factor = factor;
           }

           public static final TimeUnit PREFERRED = s;
        }

        sealed interface Quantity {
           double value();
           QuantityUnit unit();
        }

        record Length(double value, LengthUnit unit) implements Quantity {
           public String toString() {
              return value() + " " + unit();
           }
        }

        record Time(double value, TimeUnit unit) implements Quantity {
           public String toString() {
              return value() + " " + unit();
           }
        }


        public class Test3 {
           public static <T extends Quantity> T add1(T first, T second) {
              if (first instanceof Time && second instanceof Time) {
                 var v1 = first.value();
                 var u1 = ((Time) first).unit();
                 var v2 = second.value();
                 var u2 = second.unit();
                 if (u1 == u2)
                    return (T) new Time(v1 + v2, u1);
                 else
                    return (T) new Time(v1 * u1.factor() + v2 * u2.factor(),
                          TimeUnit.PREFERRED);
              }
              else if (first instanceof Length && second instanceof Length) {
                 var v1 = first.value();
                 var u1 = ((Length) first).unit();
                 var v2 = second.value();
                 var u2 = second.unit();
                 if (u1 == u2)
                    return (T) new Length(v1 + v2, u1);
                 else
                    return (T) new Length(v1 * u1.factor() + v2 * u2.factor(),
                          LengthUnit.PREFERRED);
              }
              else
                 return null; // cannot happen
           }

           public static <T extends Quantity> T add2(T first, T second) {
              if (first instanceof Time(var v1, var u1) && second instanceof Time(var v2, var u2)) {
                 if (u1 == u2) return (T) new Time(v1 + v2, u1);
                 else return (T) new Time(v1 * u1.factor() + v2 * u2.factor(), TimeUnit.PREFERRED);
              } else if (first instanceof Length(var v1, var u1) && second instanceof Length(var v2, var u2)) {
                 if (u1 == u2) return (T) new Length(v1 + v2, u1);
                 else return (T) new Length(v1 * u1.factor() + v2 * u2.factor(), LengthUnit.PREFERRED);
              }
              else return null; // cannot happen
           }
           
           public static void main(String[] args) {
              System.out.println(add1(new Time(1, TimeUnit.h), new Time(1, TimeUnit.min)));
           }
        }

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

        CUSTOMER SUBMITTED WORKAROUND :
        Don't use pattern matching.

        FREQUENCY : always


        Attachments

          Issue Links

            Activity

              People

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

                Dates

                  Created:
                  Updated:
                  Resolved: