You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@groovy.apache.org by "Olof Asbrink (Jira)" <ji...@apache.org> on 2022/11/28 15:04:00 UTC

[jira] [Created] (GROOVY-10857) Compiler enter infinite loop when compiling circular meta annotations

Olof Asbrink created GROOVY-10857:
-------------------------------------

             Summary: Compiler enter infinite loop when compiling circular meta annotations
                 Key: GROOVY-10857
                 URL: https://issues.apache.org/jira/browse/GROOVY-10857
             Project: Groovy
          Issue Type: Bug
          Components: Compiler
    Affects Versions: 4.0.6
         Environment: Groovy 4.0.6, openjdk 17.0.4.1, Guava 31.1-jre

            Reporter: Olof Asbrink


When I compile groovy that uses Java classes that has circular meta annotations in their class hierarcy. The compile crash with:
{code:java}
>>> 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)
... {code}
this can be produced with this small example (2 java files and 1 groovy file):

MyMetaAnnotation.java:
{code: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 {} {code}
MyAnnotation.java:
{code: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 {} {code}
and UseMyAnnotation.groovy
{code:java}
import MyAnnotation

public interface A<T> {
      @MyAnnotation
      T a()
}
      
def b = new A() {
    def a() { return 0 }
} {code}
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:
{code:java}
import com.google.common.base.Supplier

def zeroSupplier = new Supplier() {
    def get() { return 0 }
}
{code}
Note that circularity in meta annotations is permitted according to the java spec:
{quote}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.
{quote}
(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

 

 



--
This message was sent by Atlassian Jira
(v8.20.10#820010)