Uploaded image for project: 'Groovy'
  1. Groovy
  2. GROOVY-10857

Compiler enter infinite loop when compiling circular meta annotations

    XMLWordPrintableJSON

Details

    • Bug
    • Status: Closed
    • Major
    • Resolution: Fixed
    • 4.0.6
    • 4.0.7
    • Compiler
    • Groovy 4.0.6, openjdk 17.0.4.1, Guava 31.1-jre

    Description

      When I compile groovy that uses Java classes that has circular meta annotations in their class hierarcy. The compile crash with:

      >>> a serious error occurred: null
      >>> stacktrace:
      java.lang.StackOverflowError
              at java.base/java.util.stream.ReferencePipeline.forEachWithCancel(ReferencePipeline.java:129)
              at java.base/java.util.stream.AbstractPipeline.copyIntoWithCancel(AbstractPipeline.java:527)
              at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:513)
              at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
              at java.base/java.util.stream.MatchOps$MatchOp.evaluateSequential(MatchOps.java:230)
              at java.base/java.util.stream.MatchOps$MatchOp.evaluateSequential(MatchOps.java:196)
              at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
              at java.base/java.util.stream.ReferencePipeline.anyMatch(ReferencePipeline.java:632)
              at org.codehaus.groovy.ast.ClassNode.<init>(ClassNode.java:349)
              at org.codehaus.groovy.ast.ClassNode.<init>(ClassNode.java:327)
              at org.codehaus.groovy.ast.ClassHelper.makeWithoutCaching(ClassHelper.java:281)
              at org.apache.groovy.contracts.util.AnnotationUtils.hasMetaAnnotations(AnnotationUtils.java:123)
              at org.apache.groovy.contracts.util.AnnotationUtils.hasMetaAnnotations(AnnotationUtils.java:125)
              at org.apache.groovy.contracts.util.AnnotationUtils.hasMetaAnnotations(AnnotationUtils.java:125)
              at org.apache.groovy.contracts.util.AnnotationUtils.hasMetaAnnotations(AnnotationUtils.java:125)
              at org.apache.groovy.contracts.util.AnnotationUtils.hasMetaAnnotations(AnnotationUtils.java:125)
              at org.apache.groovy.contracts.util.AnnotationUtils.hasMetaAnnotations(AnnotationUtils.java:125)
              at org.apache.groovy.contracts.util.AnnotationUtils.hasMetaAnnotations(AnnotationUtils.java:125)
              at org.apache.groovy.contracts.util.AnnotationUtils.hasMetaAnnotations(AnnotationUtils.java:125)
      ... 

      this can be produced with this small example (2 java files and 1 groovy file):

      MyMetaAnnotation.java:

      import static java.lang.annotation.ElementType.TYPE;
      import static java.lang.annotation.ElementType.METHOD;
      import static java.lang.annotation.RetentionPolicy.RUNTIME;
      
      import java.lang.annotation.Retention;
      import java.lang.annotation.Target;
      
      @Retention(RUNTIME)
      @Target({TYPE, METHOD})
      @MyMetaAnnotation
      public @interface MyMetaAnnotation {} 

      MyAnnotation.java:

      import static java.lang.annotation.ElementType.FIELD;
      import static java.lang.annotation.ElementType.METHOD;
      import static java.lang.annotation.ElementType.PARAMETER;
      import static java.lang.annotation.RetentionPolicy.RUNTIME;
      
      import java.lang.annotation.Retention;
      import java.lang.annotation.Target;
      
      @MyMetaAnnotation
      @Retention(RUNTIME)
      @Target({FIELD, METHOD, PARAMETER})
      public @interface MyAnnotation {} 

      and UseMyAnnotation.groovy

      import MyAnnotation
      
      public interface A<T> {
            @MyAnnotation
            T a()
      }
            
      def b = new A() {
          def a() { return 0 }
      } 

      A real world example is using some Guava classes which several has circularities in their meta annotations (e.g. com.google.common.base.Supplier) . This example will yield the same stackoverflow:

      import com.google.common.base.Supplier
      
      def zeroSupplier = new Supplier() {
          def get() { return 0 }
      }
      

      Note that circularity in meta annotations is permitted according to the java spec:

      An annotation of interface A may appear as a meta-annotation on the declaration of the interface A itself. More generally, circularities in the transitive closure of the "annotates" relation are permitted.

      (from https://docs.oracle.com/javase/specs/jls/se17/html/jls-9.html#jls-9.7.1)

       

      Also note. These compile succesfully using Groovy 3.0.11

       

       

      Attachments

        Activity

          People

            emilles Eric Milles
            olofasbrink Olof Asbrink
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved: