Groovy
  1. Groovy
  2. GROOVY-7836

CompileStatic + static inner class + EqualsAndHashCode gives VerifyError in equals

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 2.4.6
    • Fix Version/s: 2.4.7
    • Component/s: Static compilation
    • Labels:
      None

      Description

      import groovy.transform.CompileStatic
      import groovy.transform.EqualsAndHashCode
      
      @CompileStatic
      class Parent {
          List<Integer> getInts() { [0] }
      
          @EqualsAndHashCode
          static class Child {
              List<Integer> ints
          }
      }
      
      println GroovySystem.version
      println new Parent.Child()
      

      The key is the inner class having a property matching the parent's.

      Result:

      2.4.6
      java.lang.VerifyError: (class: Parent$Child, method: equals signature: (Ljava/lang/Object;)Z) Incompatible object argument for function call
      

      Inspecting the bytecode, I see the following:

         L13
          ALOAD 0
          INVOKEVIRTUAL Parent.getInts ()Ljava/util/List;
          ALOAD 2
          INVOKEVIRTUAL Parent$Child.getInts ()Ljava/util/List;
          INVOKESTATIC org/codehaus/groovy/runtime/ScriptBytecodeAdapter.compareEqual (Ljava/lang/Object;Ljava/lang/Object;)Z
          IFNE L14
          ICONST_1
      

      It appears that the bytecode is attempting to call a method on the outer class, even though the inner class is static and there is no reason to access the outer class.

        Activity

        Hide
        Paul King added a comment - - edited

        Just confirming that I get the error (@CompileStatic is required to get the error) on 2.4.6 and the 2_4_X branch but not on master. I'll investigate some more when I get a chance. I haven't done a git bisect as yet.

        Bytecode corresponding to that shown above but as per master:

           L13
            LDC LParent$Child;.class
            ALOAD 0
            LDC "getInts"
            CHECKCAST java/lang/String
            INVOKESTATIC org/codehaus/groovy/runtime/ScriptBytecodeAdapter.invokeMethodOnCurrent0 (Ljava/lang/Class;Lgroovy/lang/GroovyObject;Ljava/lang/String;)Ljava/lang/Object;
            ALOAD 2
            INVOKEVIRTUAL Parent$Child.getInts ()Ljava/util/List;
            INVOKESTATIC org/codehaus/groovy/runtime/ScriptBytecodeAdapter.compareEqual (Ljava/lang/Object;Ljava/lang/Object;)Z
            IFNE L14
            ICONST_1
        
        Show
        Paul King added a comment - - edited Just confirming that I get the error (@CompileStatic is required to get the error) on 2.4.6 and the 2_4_X branch but not on master. I'll investigate some more when I get a chance. I haven't done a git bisect as yet. Bytecode corresponding to that shown above but as per master: L13 LDC LParent$Child;.class ALOAD 0 LDC "getInts" CHECKCAST java/lang/ String INVOKESTATIC org/codehaus/groovy/runtime/ScriptBytecodeAdapter.invokeMethodOnCurrent0 (Ljava/lang/ Class ;Lgroovy/lang/GroovyObject;Ljava/lang/ String ;)Ljava/lang/ Object ; ALOAD 2 INVOKEVIRTUAL Parent$Child.getInts ()Ljava/util/List; INVOKESTATIC org/codehaus/groovy/runtime/ScriptBytecodeAdapter.compareEqual (Ljava/lang/ Object ;Ljava/lang/ Object ;)Z IFNE L14 ICONST_1
        Hide
        Jason Winnebeck added a comment -

        if I read that right, the master branch is making a dynamic call to getInts followed by a static call to getInts, so it's still trying to call the method twice. I'm also confused as to why it's invoking compareEqual when it's just a getter.

        Show
        Jason Winnebeck added a comment - if I read that right, the master branch is making a dynamic call to getInts followed by a static call to getInts, so it's still trying to call the method twice. I'm also confused as to why it's invoking compareEqual when it's just a getter.
        Hide
        Jason Winnebeck added a comment -

        Sorry, I look silly for just making that comment it's in the generated equals method so of course it's calling compareEqual. But it still seems odd with compile static that the first call is "dynamic"

        Show
        Jason Winnebeck added a comment - Sorry, I look silly for just making that comment it's in the generated equals method so of course it's calling compareEqual. But it still seems odd with compile static that the first call is "dynamic"
        Hide
        John Wagenleitner added a comment -

        I checked and this was fixed in commit https://github.com/apache/groovy/commit/e4ea67c38e695fc78b4c60411322d72da2467bd0 as part of GROOVY-7813 and I verified the test code runs in 2.4.7. It looked like the tests in that commit cover this issue, so am resolving this.

        Thanks for reporting the issue.

        Show
        John Wagenleitner added a comment - I checked and this was fixed in commit https://github.com/apache/groovy/commit/e4ea67c38e695fc78b4c60411322d72da2467bd0 as part of GROOVY-7813 and I verified the test code runs in 2.4.7. It looked like the tests in that commit cover this issue, so am resolving this. Thanks for reporting the issue.
        Hide
        Jason Winnebeck added a comment -

        Thanks, I can confirm this was fixed in 2.4.7

        Show
        Jason Winnebeck added a comment - Thanks, I can confirm this was fixed in 2.4.7

          People

          • Assignee:
            Unassigned
            Reporter:
            Jason Winnebeck
          • Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development