GithubHelp home page GithubHelp logo

groovy-cps's Introduction

groovy-cps's People

Contributors

aakoch avatar abayer avatar aheritier avatar car-roll avatar dependabot[bot] avatar dwnusbaum avatar fiouz avatar jglick avatar jtnord avatar kinow avatar kohsuke avatar ndeloof avatar pauxus avatar steven-terrana avatar svanoort avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

groovy-cps's Issues

NonCPS should throw early error with CompileStatic

@NonCPS and @CompileStatic are not compatible (and possibly not @TypeChecked)--very weird errors start showing up if they're combined. If the @NonCPS processor finds that its method is affected by @CompileStatic, it should throw an error instead of trying to compile and producing unintuitive downstream errors.

Generate CpsDefaultGroovyMethods

It's silly to hand-code CpsDefaultGroovyMethods by manually doing CPS transformation.

It'd save me a lot of typing if I can apply CpsTransformer during the build process of groovy-cps itself. This way, all I need to do is to cut&paste method definitions from Groovy's DefaultGroovyMethods that has Closure in the signature.

Duplicate annotation in com.cloudbees.groovy.cps.WorkflowTransformed

Coming from jenkinsci/JenkinsPipelineUnit#426

Groovy 2.4.12

com.lesfurets.jenkins.TestSerializationCPS > testSerialization FAILED
    org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
    file:/Users/dblock/source/JenkinsPipelineUnit/dblock/src/test/jenkins/job/serializeCPS.jenkins: -1: Annotation @com.cloudbees.groovy.cps.WorkflowTransformed has RUNTIME retention and 2 occurrences. Duplicate annotations not allowed.
     @ line -1, column -1.
    1 error

Groovy 2.4.13

    java.lang.annotation.AnnotationFormatError: Duplicate annotation for class: interface com.cloudbees.groovy.cps.WorkflowTransformed: @com.cloudbees.groovy.cps.WorkflowTransformed()
        at java.base/sun.reflect.annotation.AnnotationParser.parseAnnotations2(AnnotationParser.java:126)

Error goes away in Groovy 2.4.14, but it could still be a duplicate annotation (didn't debug).

Interfaces cannot be declared

Declaring an interface breaks CPS compilation, this prevents basic OOP design in scripts

            interface Strategy {
                Closure process(Object event)
            }
            return true
java.lang.NullPointerException: Cannot invoke method visit() on null object
        at org.codehaus.groovy.runtime.NullObject.invokeMethod(NullObject.java:77)
        at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.call(PogoMetaClassSite.java:45)
        at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:42)
        at org.codehaus.groovy.runtime.callsite.NullCallSite.call(NullCallSite.java:32)
        at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:42)
        at org.codehaus.groovy.ast.stmt.BlockStatement$visit.call(Unknown Source)
        at com.cloudbees.groovy.cps.CpsTransformer.visitMethod(CpsTransformer.groovy:166)
        at sun.reflect.GeneratedMethodAccessor12.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90)
        at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:233)
        at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:361)
        at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:903)
        at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.callCurrent(PogoMetaClassSite.java:66)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:141)
        at com.cloudbees.groovy.cps.CpsTransformer$_call_closure1.doCall(CpsTransformer.groovy:95)
        at sun.reflect.GeneratedMethodAccessor11.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90)
        at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:233)
        at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:272)
        at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:903)
        at groovy.lang.Closure.call(Closure.java:415)
        at groovy.lang.Closure.call(Closure.java:428)
        at org.codehaus.groovy.runtime.DefaultGroovyMethods.each(DefaultGroovyMethods.java:1379)
        at org.codehaus.groovy.runtime.DefaultGroovyMethods.each(DefaultGroovyMethods.java:1351)
        at org.codehaus.groovy.runtime.DefaultGroovyMethods$each.call(Unknown Source)
        at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:42)
        at org.codehaus.groovy.runtime.DefaultGroovyMethods$each.call(Unknown Source)
        at com.cloudbees.groovy.cps.CpsDefaultGroovyMethods.each(CpsDefaultGroovyMethods.groovy:26)
        at sun.reflect.GeneratedMethodAccessor25.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.codehaus.groovy.runtime.metaclass.ReflectionMetaMethod.invoke(ReflectionMetaMethod.java:51)
        at org.codehaus.groovy.runtime.metaclass.NewInstanceMetaMethod.invoke(NewInstanceMetaMethod.java:54)
        at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite$PojoMetaMethodSiteNoUnwrapNoCoerce.invoke(PojoMetaMethodSite.java:271)
        at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite.call(PojoMetaMethodSite.java:53)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callSafe(AbstractCallSite.java:82)
        at com.cloudbees.groovy.cps.CpsTransformer.call(CpsTransformer.groovy:95)
        at org.codehaus.groovy.control.CompilationUnit.applyToPrimaryClassNodes(CompilationUnit.java:970)
        at org.codehaus.groovy.control.CompilationUnit.doPhaseOperation(CompilationUnit.java:548)
        at org.codehaus.groovy.control.CompilationUnit.processPhaseOperations(CompilationUnit.java:526)
        at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:503)
        at groovy.lang.GroovyClassLoader.doParseClass(GroovyClassLoader.java:302)
        at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:281)
        at groovy.lang.GroovyShell.parseClass(GroovyShell.java:731)
        at groovy.lang.GroovyShell.parse(GroovyShell.java:743)
        at groovy.lang.GroovyShell.parse(GroovyShell.java:770)
        at groovy.lang.GroovyShell.parse(GroovyShell.java:761)
        at groovy.lang.GroovyShell$parse.call(Unknown Source)

If the interface is empty, the exception is slightly different:

            interface Empty {}
            return true
Script1.groovy: -1: The field '__timeStamp' is not 'public static final' but is defined in interface 'Empty'.
 @ line -1, column -1.
1 error

        at org.codehaus.groovy.control.ErrorCollector.failIfErrors(ErrorCollector.java:302)
        at org.codehaus.groovy.control.CompilationUnit.applyToPrimaryClassNodes(CompilationUnit.java:997)
        at org.codehaus.groovy.control.CompilationUnit.doPhaseOperation(CompilationUnit.java:548)
        at org.codehaus.groovy.control.CompilationUnit.processPhaseOperations(CompilationUnit.java:526)
        at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:503)
        at groovy.lang.GroovyClassLoader.doParseClass(GroovyClassLoader.java:302)
        at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:281)
        at groovy.lang.GroovyShell.parseClass(GroovyShell.java:731)
        at groovy.lang.GroovyShell.parse(GroovyShell.java:743)
        at groovy.lang.GroovyShell.parse(GroovyShell.java:770)
        at groovy.lang.GroovyShell.parse(GroovyShell.java:761)
        at groovy.lang.GroovyShell$parse.call(Unknown Source)

Interceptor anchors for testing

During testing of the shared libraries it's really useful to be able to intercept the calls.

Reason:

All the current implementations of the Jenkins Shared Libraries unit tests are quite useless - there are a number of issues impossible to test outside of actual workflow-cps-plugin. We have the next issue about that: JENKINS-33925.

GString does not support closure with StringWriter argument under CPS

The following construct does not as expected work under CPS as the closure gets a null argument:

diff --git a/src/test/groovy/com/cloudbees/groovy/cps/CpsTransformerTest.groovy b/src/test/groovy/com/cloudbees/groovy/cps/CpsTransformerTest.groovy
index 9f45611..249f919 100644
--- a/src/test/groovy/com/cloudbees/groovy/cps/CpsTransformerTest.groovy
+++ b/src/test/groovy/com/cloudbees/groovy/cps/CpsTransformerTest.groovy
@@ -367,6 +367,14 @@ class CpsTransformerTest extends AbstractGroovyCpsTest {
     }

     @Test
+    void gstringClosureStringWriter() {
+        assert evalCPS('''
+            def x = "foo";
+            return "${ w -> w << x }".toString();
+''') == "foo";
+    }
+
+    @Test
     void ternaryOp() {
         assert evalCPS('''
             return true ? 5 : null.makeCall();

And throws the following NullPointerException:

gstringClosureStringWriter(com.cloudbees.groovy.cps.CpsTransformerTest)  Time elapsed: 0.014 sec  <<< ERROR!
java.lang.NullPointerException: Cannot invoke method leftShift() on null object
        at org.codehaus.groovy.runtime.NullObject.invokeMethod(NullObject.java:77)
        at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.call(PogoMetaClassSite.java:45)
        at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:42)
        at org.codehaus.groovy.runtime.callsite.NullCallSite.call(NullCallSite.java:32)
        at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:42)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108)
        at com.cloudbees.groovy.cps.sandbox.DefaultInvoker.methodCall(DefaultInvoker.java:15)
        at Script1.run(Script1.groovy:3)
        at Script1.run(Script1.groovy:3)
        at ___cps.transform___(Native Method)
        at com.cloudbees.groovy.cps.impl.ContinuationGroup.methodCall(ContinuationGroup.java:69)
        at com.cloudbees.groovy.cps.impl.FunctionCallBlock$ContinuationImpl.dispatchOrArg(FunctionCallBlock.java:106)
        at com.cloudbees.groovy.cps.impl.FunctionCallBlock$ContinuationImpl.fixArg(FunctionCallBlock.java:79)
        at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:497)
        at com.cloudbees.groovy.cps.impl.ContinuationPtr$ContinuationImpl.receive(ContinuationPtr.java:72)
        at com.cloudbees.groovy.cps.impl.LocalVariableBlock$LocalVariable.get(LocalVariableBlock.java:33)
        at com.cloudbees.groovy.cps.LValueBlock$GetAdapter.receive(LValueBlock.java:30)
        at com.cloudbees.groovy.cps.impl.LocalVariableBlock.evalLValue(LocalVariableBlock.java:22)
        at com.cloudbees.groovy.cps.LValueBlock$BlockImpl.eval(LValueBlock.java:55)
        at com.cloudbees.groovy.cps.LValueBlock.eval(LValueBlock.java:16)
        at com.cloudbees.groovy.cps.Next.step(Next.java:58)
        at com.cloudbees.groovy.cps.Next.run(Next.java:49)
        at com.cloudbees.groovy.cps.Next$run.call(Unknown Source)
        at com.cloudbees.groovy.cps.AbstractGroovyCpsTest.evalCPSonly(AbstractGroovyCpsTest.groovy:55)
        at com.cloudbees.groovy.cps.AbstractGroovyCpsTest.evalCPS(AbstractGroovyCpsTest.groovy:49)
        at com.cloudbees.groovy.cps.AbstractGroovyCpsTest$evalCPS.callCurrent(Unknown Source)
        at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:46)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:133)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:141)
        at com.cloudbees.groovy.cps.CpsTransformerTest.gstringClosureStringWriter(CpsTransformerTest.groovy:371)

No way to limit recursion: with bugs, GroovyCPS will consume all memory

There's no way to limit the depth of recursive calls, it just consumes ever-increasing memory as the depth grows.

The automatic conversion of field access to getter calls means that the following common lazy-loading pattern translates to an unbounded recursive call that will bring down a Jenkins master:

def something = null
def getSomething() {
  if (something == null) {
    return "someComplexComputationResult;"
  }
}
def stuff = getSomething();

We need a way to limit the depth of the recursion to prevent this scenario and handle appropriately (error out or at least pause execution and force the issue to be addressed).

Strange behaviour when NonCPS method is calling a CPS method

I did not find the exact reason or circumstances for this to happen, but I managed to create a test case showing the behaviour:

    @Test
    void nonCPSCallsCPSMethod() {
        evalCPS('''
            class Foo {
                int count
            
                @NonCPS
                static Foo create(int value) {
                    def aList = [5,6,7,8].collect { new Foo(count: it) }
                    return aList.find { it.matches(value) }
                }
                
                boolean matches(int value) {
                    count == value
                }
            }
            
            Foo.create(7)
        ''')
    }

This fails in the evalCPS test method. The CPS version returns a Boolean, while the NonCPS version correctly returns a Foo instance.

Of course, a NonCPS method calling a CPS method might be considered questionable, but in that case at least the compiliation and/or the execution should fail with a meaningful exception.

Failing unit test & Travis integration ?

Hello.

The following test is failing when I clone & run mvn test in this repo,
with Java 1.8.0_40 and Groovy 2.4.8 : https://github.com/cloudbees/groovy-cps/blob/master/src/test/groovy/com/cloudbees/groovy/cps/AbstractGroovyCpsTest.groovy#L50

Tests run: 46, Failures: 1, Errors: 0, Skipped: 2, Time elapsed: 3.561 sec <<< FAILURE!
each(com.cloudbees.groovy.cps.CpsTransformerTest)  Time elapsed: 0.031 sec  <<< FAILURE!
Assertion failed:

assert v==sh.evaluate(script)
       || |  |        |
       0| |  55
        | |               def x = 0;
        | |               (0..10).each { y -> x+=y; }
        | |               return x;
        | groovy.lang.GroovyShell@37ddb69a
        false

        at org.codehaus.groovy.runtime.InvokerHelper.assertFailed(InvokerHelper.java:386)
        at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.assertFailed(ScriptBytecodeAdapter.java:658)
        at com.cloudbees.groovy.cps.AbstractGroovyCpsTest.evalCPS(AbstractGroovyCpsTest.groovy:50)
        at com.cloudbees.groovy.cps.AbstractGroovyCpsTest$evalCPS.callCurrent(Unknown Source)
        at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:46)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:133)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:141)
        at com.cloudbees.groovy.cps.CpsTransformerTest.each(CpsTransformerTest.groovy:407)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:497)
        at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
        at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
        at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
        at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
        at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
        at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
        at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
        at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
        at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
        at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
        at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
        at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
        at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
        at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
        at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:252)
        at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:141)
        at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:112)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:497)
        at org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:189)
        at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:165)
        at org.apache.maven.surefire.booter.ProviderFactory.invokeProvider(ProviderFactory.java:85)
        at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:115)
        at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:75)

Also, what do you think about adding enabling Travis CI tests for thir repo ?

[JENKINS-39329] Abstract methods lead to NPEs

When transforming an abstract class with abstract methods

abstract class Parent {
  abstract void run()
}

This leads to a Nullpointer Exception:

BUG! exception in phase 'semantic analysis' in source unit 'WorkflowScript' exception in phase 'canonicalization' in source unit 'file:/d:/jenkins/jobs/GitTest/jobs/RC-Build/builds/39/libs/PipelineLibrary/src/com/gfk/st2/build/pipeline/pipeline/Pipeline.groovy' unexpected NullpointerException
    at org.codehaus.groovy.control.CompilationUnit.applyToPrimaryClassNodes(CompilationUnit.java:1058)
    at org.codehaus.groovy.control.CompilationUnit.doPhaseOperation(CompilationUnit.java:591)
    at org.codehaus.groovy.control.CompilationUnit.processPhaseOperations(CompilationUnit.java:569)
    at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:546)
    at groovy.lang.GroovyClassLoader.doParseClass(GroovyClassLoader.java:298)
    at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:268)
    at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:254)
    at groovy.lang.GroovyClassLoader.recompile(GroovyClassLoader.java:761)
    at groovy.lang.GroovyClassLoader.loadClass(GroovyClassLoader.java:718)
    at groovy.lang.GroovyClassLoader.loadClass(GroovyClassLoader.java:787)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at groovy.lang.GroovyClassLoader.loadClass(GroovyClassLoader.java:677)
    at groovy.lang.GroovyClassLoader.loadClass(GroovyClassLoader.java:545)
    at org.codehaus.groovy.control.ClassNodeResolver.tryAsLoaderClassOrScript(ClassNodeResolver.java:185)
    at org.codehaus.groovy.control.ClassNodeResolver.findClassNode(ClassNodeResolver.java:170)
    at org.codehaus.groovy.control.ClassNodeResolver.resolveName(ClassNodeResolver.java:126)
    at org.codehaus.groovy.control.ResolveVisitor.resolveToOuter(ResolveVisitor.java:676)
    at org.codehaus.groovy.control.ResolveVisitor.resolve(ResolveVisitor.java:308)
    at org.codehaus.groovy.control.ResolveVisitor.resolveFromModule(ResolveVisitor.java:638)
    at org.codehaus.groovy.control.ResolveVisitor.resolve(ResolveVisitor.java:308)
    at org.codehaus.groovy.control.ResolveVisitor.resolve(ResolveVisitor.java:276)
    at org.codehaus.groovy.control.ResolveVisitor.resolveOrFail(ResolveVisitor.java:260)
    at org.codehaus.groovy.control.ResolveVisitor.resolveOrFail(ResolveVisitor.java:272)
    at org.codehaus.groovy.control.ResolveVisitor.transformConstructorCallExpression(ResolveVisitor.java:1047)
    at org.codehaus.groovy.control.ResolveVisitor.transform(ResolveVisitor.java:706)
    at org.codehaus.groovy.ast.ClassCodeExpressionTransformer.visitExpressionStatement(ClassCodeExpressionTransformer.java:142)
    at org.codehaus.groovy.ast.stmt.ExpressionStatement.visit(ExpressionStatement.java:42)
    at org.codehaus.groovy.ast.CodeVisitorSupport.visitBlockStatement(CodeVisitorSupport.java:37)
    at org.codehaus.groovy.ast.ClassCodeVisitorSupport.visitBlockStatement(ClassCodeVisitorSupport.java:166)
    at org.codehaus.groovy.control.ResolveVisitor.visitBlockStatement(ResolveVisitor.java:1318)
    at org.codehaus.groovy.ast.stmt.BlockStatement.visit(BlockStatement.java:71)
    at org.codehaus.groovy.ast.ClassCodeVisitorSupport.visitClassCodeContainer(ClassCodeVisitorSupport.java:104)
    at org.codehaus.groovy.ast.ClassCodeVisitorSupport.visitConstructorOrMethod(ClassCodeVisitorSupport.java:115)
    at org.codehaus.groovy.ast.ClassCodeExpressionTransformer.visitConstructorOrMethod(ClassCodeExpressionTransformer.java:53)
    at org.codehaus.groovy.control.ResolveVisitor.visitConstructorOrMethod(ResolveVisitor.java:201)
    at org.codehaus.groovy.ast.ClassCodeVisitorSupport.visitMethod(ClassCodeVisitorSupport.java:126)
    at org.codehaus.groovy.ast.ClassNode.visitContents(ClassNode.java:1078)
    at org.codehaus.groovy.ast.ClassCodeVisitorSupport.visitClass(ClassCodeVisitorSupport.java:53)
    at org.codehaus.groovy.control.ResolveVisitor.visitClass(ResolveVisitor.java:1261)
    at org.codehaus.groovy.control.ResolveVisitor.startResolving(ResolveVisitor.java:176)
    at org.codehaus.groovy.control.CompilationUnit$11.call(CompilationUnit.java:651)
    at org.codehaus.groovy.control.CompilationUnit.applyToSourceUnits(CompilationUnit.java:931)
    at org.codehaus.groovy.control.CompilationUnit.doPhaseOperation(CompilationUnit.java:593)
    at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:542)
    at groovy.lang.GroovyClassLoader.doParseClass(GroovyClassLoader.java:298)
    at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:268)
    at groovy.lang.GroovyShell.parseClass(GroovyShell.java:688)
    at groovy.lang.GroovyShell.parse(GroovyShell.java:700)
    at org.jenkinsci.plugins.workflow.cps.CpsGroovyShell.reparse(CpsGroovyShell.java:67)
    at org.jenkinsci.plugins.workflow.cps.CpsFlowExecution.parseScript(CpsFlowExecution.java:411)
    at org.jenkinsci.plugins.workflow.cps.CpsFlowExecution.start(CpsFlowExecution.java:374)
    at org.jenkinsci.plugins.workflow.job.WorkflowRun.run(WorkflowRun.java:220)
    at hudson.model.ResourceController.execute(ResourceController.java:98)
    at hudson.model.Executor.run(Executor.java:404)
Caused by: java.lang.NullPointerException: Cannot get property 'lineNumber' on null object
    at org.codehaus.groovy.runtime.NullObject.getProperty(NullObject.java:60)
    at org.codehaus.groovy.runtime.InvokerHelper.getProperty(InvokerHelper.java:172)
    at org.codehaus.groovy.runtime.callsite.NullCallSite.getProperty(NullCallSite.java:47)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callGetProperty(AbstractCallSite.java:296)
    at com.cloudbees.groovy.cps.CpsTransformer.loc(CpsTransformer.groovy:351)
    at sun.reflect.GeneratedMethodAccessor63.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93)
    at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325)
    at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:384)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1024)
    at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.callCurrent(PogoMetaClassSite.java:69)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:166)
    at com.cloudbees.groovy.cps.CpsTransformer$_visitWithSafepoint_closure6_closure49_closure50.doCall(CpsTransformer.groovy:292)
    at sun.reflect.GeneratedMethodAccessor157.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93)
    at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325)
    at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:294)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1024)
    at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.callCurrent(PogoMetaClassSite.java:69)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:166)
    at com.cloudbees.groovy.cps.CpsTransformer$_visitWithSafepoint_closure6_closure49_closure50.doCall(CpsTransformer.groovy)
    at sun.reflect.GeneratedMethodAccessor156.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93)
    at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325)
    at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:294)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1024)
    at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.call(PogoMetaClassSite.java:42)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
    at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.call(PogoMetaClassSite.java:57)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:117)
    at com.cloudbees.groovy.cps.CpsTransformer.makeChildren(CpsTransformer.groovy:336)
    at sun.reflect.GeneratedMethodAccessor62.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite$PogoCachedMethodSiteNoUnwrapNoCoerce.invoke(PogoMetaMethodSite.java:210)
    at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite.callCurrent(PogoMetaMethodSite.java:59)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:52)
    at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite.callCurrent(PogoMetaMethodSite.java:64)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:166)
    at com.cloudbees.groovy.cps.CpsTransformer.makeNode(CpsTransformer.groovy:311)
    at sun.reflect.GeneratedMethodAccessor61.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93)
    at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325)
    at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:384)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1024)
    at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.callCurrent(PogoMetaClassSite.java:69)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:174)
    at com.cloudbees.groovy.cps.CpsTransformer$_visitWithSafepoint_closure6_closure49.doCall(CpsTransformer.groovy:291)
    at sun.reflect.GeneratedMethodAccessor155.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93)
    at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325)
    at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:294)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1024)
    at groovy.lang.Closure.call(Closure.java:414)
    at groovy.lang.Closure.call(Closure.java:430)
    at org.codehaus.groovy.runtime.DefaultGroovyMethods.each(DefaultGroovyMethods.java:2030)

This happens because visitMethod() tries to parse the statements of the method, which are clearly null.

This could be easily solved by enhancing CpsTransformer.shouldBeTransformed() with a check for abstractness.

I will provide a PR for this.

Closure.rehydrate() does not affect call resolution of the resulting closure

The following script does not executes as expected as the speak() call cannot be resolved against the Script instance:

            class MyStrategy {
                Closure<String> process() {
                    return {
                        speak()
                    }
                }
            }
            String speak() {
                'from Script instance'
            }
            Closure<String> closure = new MyStrategy().process()
            closure.rehydrate(this, this, this).call()

The resolution is done against the original scope:

groovy.lang.MissingMethodException: No signature of method: MyStrategy.speak() is applicable for argument types: () values: []
Possible solutions: split(groovy.lang.Closure), sleep(long), sleep(long, groovy.lang.Closure), inspect(), every(), grep()
        at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:55)
        at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.call(PogoMetaClassSite.java:51)
        at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:42)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108)
        at com.cloudbees.groovy.cps.sandbox.DefaultInvoker.methodCall(DefaultInvoker.java:15)
        at MyStrategy.process(Script1.groovy:5)
        at Script1.run(Script1.groovy:13)
        at ___cps.transform___(Native Method)
        at com.cloudbees.groovy.cps.impl.ContinuationGroup.methodCall(ContinuationGroup.java:48)
        at com.cloudbees.groovy.cps.impl.FunctionCallBlock$ContinuationImpl.dispatchOrArg(FunctionCallBlock.java:106)
        at com.cloudbees.groovy.cps.impl.FunctionCallBlock$ContinuationImpl.fixName(FunctionCallBlock.java:74)
        at sun.reflect.GeneratedMethodAccessor4.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at com.cloudbees.groovy.cps.impl.ContinuationPtr$ContinuationImpl.receive(ContinuationPtr.java:72)
        at com.cloudbees.groovy.cps.impl.ConstantBlock.eval(ConstantBlock.java:21)
        at com.cloudbees.groovy.cps.Next.step(Next.java:58)
        at com.cloudbees.groovy.cps.Next.run(Next.java:49)
        at com.cloudbees.groovy.cps.Next$run.call(Unknown Source)
        at com.cloudbees.groovy.cps.AbstractGroovyCpsTest.evalCPSonly(AbstractGroovyCpsTest.groovy:55)
        at com.cloudbees.groovy.cps.AbstractGroovyCpsTest.evalCPS(AbstractGroovyCpsTest.groovy:49)
        at com.cloudbees.groovy.cps.AbstractGroovyCpsTest$evalCPS.callCurrent(Unknown Source)

List to constructor coercion not supported

Maybe a consequence of #12 (incomplete type checking), CPS does not support constructor list:

http://groovy-lang.org/semantics.html#_list_and_map_constructors

In addition to the assignment rules above, if an assignment is deemed invalid, in type checked mode, a list literal or a map literal A can be assigned to a variable of type T if:
the assignment is a variable declaration and A is a list literal and T has a constructor whose parameters match the types of the elements in the list literal

        assert evalCPS('''\
            File f = ['/parent', 'name']
            return f
        '''.stripIndent()) == new File('/parent', 'name')

The CPS execution return value is actually the List instance not being converted to a proper File:

Assertion failed: 

assert resultInCps==sh.evaluate(script)
       |          | |  |        |
       |          | |  |        File f = ['/parent', 'name']
       |          | |  |        return f
       |          | |  \parent\name
       |          | groovy.lang.GroovyShell@14a002b1
       |          false
       [/parent, name]

CPS Mismatches

Hello,

Following the introduction of a new warning log message in version 2.7.1 of the Pipeline:Groovy plugin, we are now receiving types of the following warning in builds using the Artifactory Plugin:
expected to call org.jfrog.hudson.pipeline.common.types.ArtifactoryServer.upload but wound up catching artifactoryUpload

The pipeline API supported by the Artifactory plugin creates objects, on which methods can be invoked.
For example:

def server = Artifactory.server 'my-server'
server.upload ...

Notice that the 'server' object allows executing the 'artifactoryUpload' step.
This OOP style is very convenient and allows reusing code and configuration. This approach received very positive feedbacks since it was introduced.
Currently however, this is achieved by having the 'server' instance store the CpsScript, so that it can be used to invoke the step (by using ‘cpsScript.invokeMethod').

The Artifactory pipeline API is available for a few years already and has become extremely popular.
We would appreciate your advice on how to change the plugin in a way that will both satisfy the CPS guidelines without breaking its current functionality and structure.

Thank you

CompileStatic only works on methods

Hey Team,

I've been getting CPS errors when trying to use @CompileStatic at the class level. When I move the attribute to each method, the transformation succeeds.

Example Class

I'd like to add @CompileStatic to all compatible classes, but it's a bit inconvenient to add the attribute to every method. Especially my Unit Test classes.

Let me know if I'm using this incorrectly, or if it's not worth using on a CPS transformed class.

Strange issue with attribute vs. propertyBlocks

The following code does work without transformation:

import groovy.transform.InheritConstructors

abstract class Parent {
    abstract String getName()
}
    
class Child extends Parent {
    String name
    
    int getLength() {
        return name.length()
    }
}

@InheritConstructors            
class GC extends Child {
}

assert new GC(name: 'hallo').getLength() == 5

However, when tranforming it results in:

groovy.lang.MissingFieldException: No such field: name for class: GC

|tat groovy.lang.MetaClassImpl.getAttribute(MetaClassImpl.java:2518)
|tat groovy.lang.MetaClassImpl.getAttribute(MetaClassImpl.java:3351)
|tat org.codehaus.groovy.runtime.InvokerHelper.getAttribute(InvokerHelper.java:129)
|tat org.codehaus.groovy.runtime.ScriptBytecodeAdapter.getField(ScriptBytecodeAdapter.java:302)
|tat com.cloudbees.groovy.cps.sandbox.DefaultInvoker.getAttribute(DefaultInvoker.java:42)
|tat com.cloudbees.groovy.cps.impl.AttributeAccessBlock.rawGet(AttributeAccessBlock.java:20)
|tat Child.getLength(Script1.groovy:12)
|tat Script1.run(Script1.groovy:20)
|tat ___cps.transform___(Native Method)
|tat com.cloudbees.groovy.cps.impl.PropertyishBlock$ContinuationImpl.get(PropertyishBlock.java:74)
|tat com.cloudbees.groovy.cps.LValueBlock$GetAdapter.receive(LValueBlock.java:30)
|tat com.cloudbees.groovy.cps.impl.PropertyishBlock$ContinuationImpl.fixName(PropertyishBlock.java:66)
|tat sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
|tat sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
|tat sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
|tat java.lang.reflect.Method.invoke(Method.java:498)
|tat com.cloudbees.groovy.cps.impl.ContinuationPtr$ContinuationImpl.receive(ContinuationPtr.java:72)
|tat com.cloudbees.groovy.cps.impl.ConstantBlock.eval(ConstantBlock.java:21)
|tat com.cloudbees.groovy.cps.Next.step(Next.java:74)
|tat com.cloudbees.groovy.cps.Next.run(Next.java:65)
|tat com.cloudbees.groovy.cps.Next$run.call(Unknown Source)
|tat org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:42)
|tat org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108)
|tat org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
|tat com.cloudbees.groovy.cps.AbstractGroovyCpsTest.evalCPSonly(AbstractGroovyCpsTest.groovy:55)
|tat com.cloudbees.groovy.cps.AbstractGroovyCpsTest.evalCPS(AbstractGroovyCpsTest.groovy:49)
|tat com.cloudbees.groovy.cps.AbstractGroovyCpsTest$evalCPS.callCurrent(Unknown Source)
|tat org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:46)
|tat org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:133)
|tat org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:141)
|tat com.cloudbees.groovy.cps.CpsTransformerTest.nonCPSCallsCPSMethod(CpsTransformerTest.groovy:768)
|tat sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
|tat sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
|tat sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
|tat java.lang.reflect.Method.invoke(Method.java:498)
|tat org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
|tat org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
|tat org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
|tat org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
|tat org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
|tat org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
|tat org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
|tat org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
|tat org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
|tat org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
|tat org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
|tat org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
|tat org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
|tat org.junit.runners.ParentRunner.run(ParentRunner.java:309)
|tat org.junit.runner.JUnitCore.run(JUnitCore.java:160)
|tat com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
|tat com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
|tat com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
|tat com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)

When replacing the assert with:

assert new Child(name: 'hallo').getLength() == 5

it works though.

ArrayList.each method dispatch is buggy

Sequence.each correctly dispatches to CpsDefaultGroovyMethods.each, but somehow ArrayList.each isn't dispatching to that method. Instead, it finds DefaultGroovyMethods.each.

Presumably the way we register CpsDefaultGroovyMethods methods into Groovy runtime is incorrect, and the method dispatch cache for ArrayList contains stale entry.

To fix this issue, either figure out how to insert meta-method into Groovy, or figure out how to clean up stale cache.

CPS transformation should honor the return type signature

CPS transformation ignores the declared return type of function, and always treat as if it is typed as Object.

This creates a behaviour difference between normal Groovy code vs CPS-transformed code.

int foo() { return "abc" }
foo();  // compiles fine but at runtime throws ClassCastException

void bar() { 42; }
x=bar(); // runs fine but assigns null

This should be relatively easy by having Continuation check the type of the value (or substitute it by null in case of void methods)

Resolving super to wrong class

Hi, I am working on the simpletravisrunner plugin and I have something like this:

class SimpleTravisRunner implements Serializable {
    [...]
    public void call(String path, String labelExpr = null, Integer timeout = 50, scm = null) {
        [...]
        script.node(label) {
            TravisScriptExecutorFactory executorFactory = new TravisScriptExecutorFactory()
            TravisScriptExecutor executor = executorFactory.getExecutorInstance(script, travisSteps)

            executor.loadData()
            executor.execute()
        }
    }

    private SimpleTravisRunner getSimpleTravisRunner() {
        return this
    }

    interface TravisScriptExecutor {
        public void loadData()
        public void execute()
    }

    class TravisScriptExecutorFactory implements Serializable {
        private static final def executorsMap = [
            generic: GenericTravisScriptExecutor,
            go: LanguageGoEnvironment,
        ]

        TravisScriptExecutorFactory() {}

        TravisScriptExecutor getExecutorInstance(CpsScript script, Map<String, Object> travisYml) {
            TravisScriptExecutor executor = null
            if (travisYml.containsKey("language") && executorsMap.containsKey(travisYml.get("language"))) {
                executor = executorsMap \
                    .get(travisYml.get("language")) \
                    .newInstance(getSimpleTravisRunner(), script, travisYml)
            } else {
                executor = executorsMap \
                    .get("generic") \
                    .newInstance(getSimpleTravisRunner(), script, travisYml)
            }

            return executor
        }
    }

    class GenericTravisScriptExecutor implements TravisScriptExecutor, Serializable {
        [...]
        GenericTravisScriptExecutor(CpsScript script, Map<String, Object> travisYml) {
            this.script = script
            this.travisYml = travisYml
        }
        [...]
        void loadData() {
            envMatrix = new TravisEnvMatrix(defaultEnv, script)

            if (travisYml.containsKey("env")) {
                generateEnvMatrix(travisYml.get("env"), envMatrix)
            }
        }
        [...]
        void execute() {
            [...]
        }
        [...]
    }

    class LanguageGoEnvironment extends GenericTravisScriptExecutor {
        [...]
        LanguageGoEnvironment(CpsScript script, Map<String, Object> travisYml) {
            super(script, travisYml)
        }
        [...]
        @Override
        void loadData() {
            super.loadData()  // Code fails here.
            [...]
        }

        @Override
        void execute() {
            script.dir(projPath) {
                super.loadData()
            }
        }
        [...]
    }
}

I left in this code the relevant parts. It fails with this message:

hudson.remoting.ProxyException: org.codehaus.groovy.runtime.InvokerInvocationException: groovy.lang.MissingMethodException: No signature of method: org.jenkinsci.plugins.simpletravisrunner.SimpleTravisRunner.loadData() is applicable for argument types: () values: []
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:97)
at groovy.lang.MetaClassImpl.invokeMissingMethod(MetaClassImpl.java:830)
at groovy.lang.MetaClassImpl.invokePropertyOrMissing(MetaClassImpl.java:1128)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1081)
at com.cloudbees.groovy.cps.sandbox.DefaultInvoker.superCall(DefaultInvoker.java:29)
at org.jenkinsci.plugins.simpletravisrunner.SimpleTravisRunner$LanguageGoEnvironment.loadData(jar:file:/var/jenkins_home/plugins/simple-travis-runner/WEB-INF/lib/simple-travis-runner.jar!/org/jenkinsci/plugins/simpletravisrunner/SimpleTravisRunner.groovy:564)
at org.jenkinsci.plugins.simpletravisrunner.SimpleTravisRunner.call(jar:file:/var/jenkins_home/plugins/simple-travis-runner/WEB-INF/lib/simple-travis-runner.jar!/org/jenkinsci/plugins/simpletravisrunner/SimpleTravisRunner.groovy:108)
at ___cps.transform___(Native Method)
at com.cloudbees.groovy.cps.impl.ContinuationGroup.methodCall(ContinuationGroup.java:54)
at com.cloudbees.groovy.cps.impl.FunctionCallBlock$ContinuationImpl.dispatchOrArg(FunctionCallBlock.java:109)
at com.cloudbees.groovy.cps.impl.FunctionCallBlock$ContinuationImpl.fixName(FunctionCallBlock.java:77)
at sun.reflect.GeneratedMethodAccessor244.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.cloudbees.groovy.cps.impl.ContinuationPtr$ContinuationImpl.receive(ContinuationPtr.java:72)
at com.cloudbees.groovy.cps.impl.ConstantBlock.eval(ConstantBlock.java:21)
at com.cloudbees.groovy.cps.Next.step(Next.java:58)
at com.cloudbees.groovy.cps.Continuable.run0(Continuable.java:154)
at org.jenkinsci.plugins.workflow.cps.CpsThread.runNextChunk(CpsThread.java:163)
at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.run(CpsThreadGroup.java:324)
at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.access$100(CpsThreadGroup.java:78)
at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup$2.call(CpsThreadGroup.java:236)
at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup$2.call(CpsThreadGroup.java:224)
at org.jenkinsci.plugins.workflow.cps.CpsVmExecutorService$2.call(CpsVmExecutorService.java:63)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at hudson.remoting.SingleLaneExecutorService$1.run(SingleLaneExecutorService.java:112)
at jenkins.util.ContextResettingExecutorService$1.run(ContextResettingExecutorService.java:28)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Caused by: hudson.remoting.ProxyException: groovy.lang.MissingMethodException: No signature of method: org.jenkinsci.plugins.simpletravisrunner.SimpleTravisRunner.loadData() is applicable for argument types: () values: []
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:55)
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeMethodOnCurrentN(ScriptBytecodeAdapter.java:91)
at org.jenkinsci.plugins.simpletravisrunner.SimpleTravisRunner.this$dist$invoke$1(SimpleTravisRunner.groovy)
at org.jenkinsci.plugins.simpletravisrunner.SimpleTravisRunner$LanguageGoEnvironment.methodMissing(SimpleTravisRunner.groovy)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90)
at groovy.lang.MetaClassImpl.invokeMissingMethod(MetaClassImpl.java:830)
at groovy.lang.MetaClassImpl.invokePropertyOrMissing(MetaClassImpl.java:1128)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1081)
at com.cloudbees.groovy.cps.sandbox.DefaultInvoker.superCall(DefaultInvoker.java:29)
... 24 more

The thing is that the super.loadData() (from LanguageGoStrategy.loadData()) is trying to call SimpleTravisRunner.loadData(), the outer class, instead of GenericTravisScriptExecutor.loadData(), the super class. But the super constructor call is working fine.

Documentation: CPS basics, example used

CPS basics /doc/cps-basics.md seems to use for normal manner recursive function.

Will in example shown the normal-manner function factorial not recur infinitely?

Recursion seems in general to be advanced topic of programming languages. Why do CPS Basics need to use such edge-case example?
Why can't CPS Basics not use more straight forward normal-manner example, example free of recursion yet other advanced programming concepts? Is CPS possibly intended to solve problems only of advanced programming concepts?

Used example raises same or higher number of questions as number of those it solves. Reader can't learn from CPS Basics as they get confronted with open points yet before story talk really starts.

Memory use: large amounts of memory used for Env content in CallEnv implementations

CallEnv carries a 'types' array around for every instance:

private Map<String, Class> types = new HashMap<String, Class>();

The FunctionCallEnv and BlockScopeEnv and ClosureCallEnv all carry around their own independent maps of locals:

private final Map<String,Object> locals = new HashMap<String, Object>();

These maps can in aggregate be memory consuming - we should make an effort to reduce the memory footprint of CPS code by trying to remove duplication where possible and use compact maps where we can (singletonMap, emptyMap, etc).

NonCPS should target `TYPE`

When writing support classes for pipeline plugins, it's very easy to accidentally forget to apply @NonCPS to a method and end up with weird errors. Like @CompileStatic, @NonCPS should also be applicable to a whole type to treat every method as non-CPS.

CPS does not support categories

The following does not work under CPS as the up() method cannot be resolved:

diff --git a/src/test/groovy/com/cloudbees/groovy/cps/CpsTransformerTest.groovy b/src/test/groovy/com/cloudbees/groovy/cps/CpsTransformerTest.groovy
index 9f45611..5bf85d0 100644
--- a/src/test/groovy/com/cloudbees/groovy/cps/CpsTransformerTest.groovy
+++ b/src/test/groovy/com/cloudbees/groovy/cps/CpsTransformerTest.groovy
@@ -535,4 +535,18 @@ class CpsTransformerTest extends AbstractGroovyCpsTest {
         assert evalCPS("('2009' ==~ /\\d+/) as boolean")
         assert !evalCPS("('holla' ==~ /\\d+/) as boolean")
     }
+
+    @Test
+    void category() {
+        assert evalCPS('''
+            class BarCategory {
+                static String up(String text) {
+                    text.toUpperCase()
+                }
+            }
+            return use(BarCategory) {
+                'foo'.up()
+            };
+''') == 'FOO';
+    }
 }

category(com.cloudbees.groovy.cps.CpsTransformerTest)  Time elapsed: 0.027 sec  <<< ERROR!
groovy.lang.MissingMethodException: No signature of method: java.lang.String.up() is applicable for argument types: () values: []
Possible solutions: dump(), use([Ljava.lang.Object;), is(java.lang.Object), use(java.lang.Class, groovy.lang.Closure), tr(java.lang.String, java.lang.String), tr(java.lang.CharSequence, java.lang.CharSequence)
    at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:55)
    at org.codehaus.groovy.runtime.callsite.PojoMetaClassSite.call(PojoMetaClassSite.java:46)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:42)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108)
    at com.cloudbees.groovy.cps.sandbox.DefaultInvoker.methodCall(DefaultInvoker.java:15)
    at Script1.run(Script1.groovy:8)
    at Script1.run(Script1.groovy:7)
    at ___cps.transform___(Native Method)
    at com.cloudbees.groovy.cps.impl.ContinuationGroup.methodCall(ContinuationGroup.java:69)
    at com.cloudbees.groovy.cps.impl.FunctionCallBlock$ContinuationImpl.dispatchOrArg(FunctionCallBlock.java:106)
    at com.cloudbees.groovy.cps.impl.FunctionCallBlock$ContinuationImpl.fixName(FunctionCallBlock.java:74)
    at sun.reflect.GeneratedMethodAccessor4.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at com.cloudbees.groovy.cps.impl.ContinuationPtr$ContinuationImpl.receive(ContinuationPtr.java:72)
    at com.cloudbees.groovy.cps.impl.ConstantBlock.eval(ConstantBlock.java:21)
    at com.cloudbees.groovy.cps.Next.step(Next.java:58)
    at com.cloudbees.groovy.cps.Next.run(Next.java:49)
    at com.cloudbees.groovy.cps.Next$run.call(Unknown Source)
    at com.cloudbees.groovy.cps.AbstractGroovyCpsTest.evalCPSonly(AbstractGroovyCpsTest.groovy:55)
    at com.cloudbees.groovy.cps.AbstractGroovyCpsTest.evalCPS(AbstractGroovyCpsTest.groovy:49)
    at com.cloudbees.groovy.cps.AbstractGroovyCpsTest$evalCPS.callCurrent(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:46)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:133)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:141)
    at com.cloudbees.groovy.cps.CpsTransformerTest.category(CpsTransformerTest.groovy:541)

Incorrect return value from `vars` step

I have a custom step, listed in its entirety below. The return value is explicitly specified as boolean, and I'm returning a boolean expression, but CPS turns the return into an Integer (0/1), which then causes failures downstream (since the sandbox won't coerce back to a boolean).

@NonCPS
boolean call(String remote = UPSTREAM_REMOTE, String branch = UPSTREAM_BRANCH) {
  def retVal = sh returnStatus: true, script: "git merge-base --is-ancestor HEAD $remote/$branch"
  return (retVal == 0)
}

CCE when using a GString with a dynamic method pointer

When using a GString to resolve a method pointer, I am getting the below CCE:

java.lang.ClassCastException: org.codehaus.groovy.runtime.GStringImpl cannot be cast to java.lang.String
	at com.cloudbees.groovy.cps.impl.MethodPointerBlock$ContinuationImpl.done(MethodPointerBlock.java:68)
	at sun.reflect.GeneratedMethodAccessor3870.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.lang.reflect.Method.invoke(Unknown Source)
	at com.cloudbees.groovy.cps.impl.ContinuationPtr$ContinuationImpl.receive(ContinuationPtr.java:72)
	at com.cloudbees.groovy.cps.impl.FunctionCallBlock$ContinuationImpl.dispatchOrArg(FunctionCallBlock.java:103)
	at com.cloudbees.groovy.cps.impl.FunctionCallBlock$ContinuationImpl.fixArg(FunctionCallBlock.java:82)
	at sun.reflect.GeneratedMethodAccessor209.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.lang.reflect.Method.invoke(Unknown Source)
	at com.cloudbees.groovy.cps.impl.ContinuationPtr$ContinuationImpl.receive(ContinuationPtr.java:72)
	at WorkflowScript.run(WorkflowScript:50)
	at ___cps.transform___(Native Method)
	at com.cloudbees.groovy.cps.impl.ContinuationGroup.methodCall(ContinuationGroup.java:60)
	at com.cloudbees.groovy.cps.impl.FunctionCallBlock$ContinuationImpl.dispatchOrArg(FunctionCallBlock.java:109)
	at com.cloudbees.groovy.cps.impl.FunctionCallBlock$ContinuationImpl.fixArg(FunctionCallBlock.java:82)
	at sun.reflect.GeneratedMethodAccessor209.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.lang.reflect.Method.invoke(Unknown Source)
	at com.cloudbees.groovy.cps.impl.ContinuationPtr$ContinuationImpl.receive(ContinuationPtr.java:72)
	at com.cloudbees.groovy.cps.impl.ConstantBlock.eval(ConstantBlock.java:21)
	at com.cloudbees.groovy.cps.Next.step(Next.java:83)
	at com.cloudbees.groovy.cps.Continuable$1.call(Continuable.java:174)
	at com.cloudbees.groovy.cps.Continuable$1.call(Continuable.java:163)
	at org.codehaus.groovy.runtime.GroovyCategorySupport$ThreadCategoryInfo.use(GroovyCategorySupport.java:122)
	at org.codehaus.groovy.runtime.GroovyCategorySupport.use(GroovyCategorySupport.java:261)
	at com.cloudbees.groovy.cps.Continuable.run0(Continuable.java:163)
	at org.jenkinsci.plugins.workflow.cps.SandboxContinuable.access$101(SandboxContinuable.java:34)
	at org.jenkinsci.plugins.workflow.cps.SandboxContinuable.lambda$run0$0(SandboxContinuable.java:59)
	at org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.GroovySandbox.runInSandbox(GroovySandbox.java:108)
	at org.jenkinsci.plugins.workflow.cps.SandboxContinuable.run0(SandboxContinuable.java:58)
	at org.jenkinsci.plugins.workflow.cps.CpsThread.runNextChunk(CpsThread.java:174)
	at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.run(CpsThreadGroup.java:332)
	at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.access$200(CpsThreadGroup.java:83)
	at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup$2.call(CpsThreadGroup.java:244)
	at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup$2.call(CpsThreadGroup.java:232)
	at org.jenkinsci.plugins.workflow.cps.CpsVmExecutorService$2.call(CpsVmExecutorService.java:64)
	at java.util.concurrent.FutureTask.run(Unknown Source)
	at hudson.remoting.SingleLaneExecutorService$1.run(SingleLaneExecutorService.java:112)
	at jenkins.util.ContextResettingExecutorService$1.run(ContextResettingExecutorService.java:28)
	at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)
	at java.util.concurrent.FutureTask.run(Unknown Source)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
	at java.lang.Thread.run(Unknown Source)
Finished: FAILURE

To reproduce, all you need to do is to get a pointer using the obj.&"$method_name" syntax, e.g., if you have a vars/test.groovy that looks like this:

def msg() {
    echo "Hello!"
}

try the below from Jenkinsfile:

def action = 'msg'
def c = test.&"$action"
c()

As a workaround, I was able to call toString() on the GString, so for the above code to work, change it to def c = test.&("$action.toString())"

NotSerializableException Spliterators$1Adapter

Seems very similar to #105

Seen in a declarative Jenkins pipeline that uses parallel stages. The issue is not reproducible, but transient and happens once in a while.

23:02:03  an exception which occurred:
23:02:03  	in field com.cloudbees.groovy.cps.impl.ForInLoopBlock$ContinuationImpl.itr
23:02:03  	in object com.cloudbees.groovy.cps.impl.ForInLoopBlock$ContinuationImpl@fa00c69
23:02:03  	in field com.cloudbees.groovy.cps.impl.ContinuationPtr$ContinuationImpl.target
23:02:03  	in object com.cloudbees.groovy.cps.impl.ContinuationPtr$ContinuationImpl@de9259b
23:02:03  	in field com.cloudbees.groovy.cps.impl.LoopBlockScopeEnv.continue_
23:02:03  	in object com.cloudbees.groovy.cps.impl.LoopBlockScopeEnv@32cc355d
23:02:03  	in field com.cloudbees.groovy.cps.impl.ProxyEnv.parent
23:02:03  	in object com.cloudbees.groovy.cps.impl.BlockScopeEnv@1310e23a
23:02:03  	in field com.cloudbees.groovy.cps.impl.CallEnv.caller
23:02:03  	in object com.cloudbees.groovy.cps.impl.FunctionCallEnv@7e3705bf
23:02:03  	in field com.cloudbees.groovy.cps.Continuable.e
23:02:03  	in object org.jenkinsci.plugins.workflow.cps.SandboxContinuable@150491f0
23:02:03  	in field org.jenkinsci.plugins.workflow.cps.CpsThread.program
23:02:03  	in object org.jenkinsci.plugins.workflow.cps.CpsThread@5d77bcdc
23:02:03  	in field org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.threads
23:02:03  	in object org.jenkinsci.plugins.workflow.cps.CpsThreadGroup@7babc0ed
23:02:03  	in object org.jenkinsci.plugins.workflow.cps.CpsThreadGroup@7babc0ed
23:02:03  Also:   an exception which occurred:
23:02:03  	in field com.cloudbees.groovy.cps.impl.ForInLoopBlock$ContinuationImpl.itr
23:02:03  	in object com.cloudbees.groovy.cps.impl.ForInLoopBlock$ContinuationImpl@fa00c69
23:02:03  	in field com.cloudbees.groovy.cps.impl.ContinuationPtr$ContinuationImpl.target
23:02:03  	in object com.cloudbees.groovy.cps.impl.ContinuationPtr$ContinuationImpl@de9259b
23:02:03  	in field com.cloudbees.groovy.cps.impl.LoopBlockScopeEnv.continue_
23:02:03  	in object com.cloudbees.groovy.cps.impl.LoopBlockScopeEnv@32cc355d
23:02:03  	in field com.cloudbees.groovy.cps.impl.ProxyEnv.parent
23:02:03  	in object com.cloudbees.groovy.cps.impl.BlockScopeEnv@3d77650f
23:02:03  	in field com.cloudbees.groovy.cps.impl.CallEnv.caller
23:02:03  	in object com.cloudbees.groovy.cps.impl.FunctionCallEnv@4efb1727
23:02:03  	in field com.cloudbees.groovy.cps.Continuable.e
23:02:03  	in object org.jenkinsci.plugins.workflow.cps.SandboxContinuable@150491f0
23:02:03  	in field org.jenkinsci.plugins.workflow.cps.CpsThread.program
23:02:03  	in object org.jenkinsci.plugins.workflow.cps.CpsThread@5d77bcdc
23:02:03  	in field org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.threads
23:02:03  	in object org.jenkinsci.plugins.workflow.cps.CpsThreadGroup@7babc0ed
23:02:03  	in object org.jenkinsci.plugins.workflow.cps.CpsThreadGroup@7babc0ed
23:02:03  	Caused: java.io.NotSerializableException: java.util.Spliterators$1Adapter
23:02:03  Also:   org.jenkinsci.plugins.workflow.steps.FlowInterruptedException
23:02:03  		at org.jenkinsci.plugins.workflow.cps.CpsBodyExecution.cancel(CpsBodyExecution.java:253)
23:02:03  		at org.jenkinsci.plugins.workflow.cps.steps.ParallelStepExecution.stop(ParallelStepExecution.java:74)
23:02:03  		at org.jenkinsci.plugins.workflow.cps.steps.ParallelStep$ResultHandler$Callback.checkAllDone(ParallelStep.java:151)
23:02:03  		at org.jenkinsci.plugins.workflow.cps.steps.ParallelStep$ResultHandler$Callback.onFailure(ParallelStep.java:138)
23:02:03  		at org.jenkinsci.plugins.workflow.cps.CpsBodyExecution$FailureAdapter.receive(CpsBodyExecution.java:361)
23:02:03  		at com.cloudbees.groovy.cps.impl.ThrowBlock$1.receive(ThrowBlock.java:68)
23:02:03  		at com.cloudbees.groovy.cps.impl.ConstantBlock.eval(ConstantBlock.java:21)
23:02:03  		at com.cloudbees.groovy.cps.Next.step(Next.java:83)
23:02:03  		at com.cloudbees.groovy.cps.Continuable$1.call(Continuable.java:174)
23:02:03  		at com.cloudbees.groovy.cps.Continuable$1.call(Continuable.java:163)
23:02:03  		at org.codehaus.groovy.runtime.GroovyCategorySupport$ThreadCategoryInfo.use(GroovyCategorySupport.java:129)
23:02:03  		at org.codehaus.groovy.runtime.GroovyCategorySupport.use(GroovyCategorySupport.java:268)
23:02:03  		at com.cloudbees.groovy.cps.Continuable.run0(Continuable.java:163)
23:02:03  		at org.jenkinsci.plugins.workflow.cps.SandboxContinuable.access$001(SandboxContinuable.java:18)
23:02:03  		at org.jenkinsci.plugins.workflow.cps.SandboxContinuable.run0(SandboxContinuable.java:51)
23:02:03  		at org.jenkinsci.plugins.workflow.cps.CpsThread.runNextChunk(CpsThread.java:185)
23:02:03  		at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.run(CpsThreadGroup.java:400)
23:02:03  		at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.access$400(CpsThreadGroup.java:96)
23:02:03  		at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup$2.call(CpsThreadGroup.java:312)
23:02:03  		at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup$2.call(CpsThreadGroup.java:276)
23:02:03  		at org.jenkinsci.plugins.workflow.cps.CpsVmExecutorService$2.call(CpsVmExecutorService.java:67)
23:02:03  Also:   org.jenkinsci.plugins.workflow.steps.FlowInterruptedException
23:02:03  		at org.jenkinsci.plugins.workflow.cps.CpsBodyExecution.cancel(CpsBodyExecution.java:253)
23:02:03  		at org.jenkinsci.plugins.workflow.cps.steps.ParallelStepExecution.stop(ParallelStepExecution.java:74)
23:02:03  		at org.jenkinsci.plugins.workflow.cps.steps.ParallelStep$ResultHandler$Callback.checkAllDone(ParallelStep.java:151)
23:02:03  		at org.jenkinsci.plugins.workflow.cps.steps.ParallelStep$ResultHandler$Callback.onFailure(ParallelStep.java:138)
23:02:03  		at org.jenkinsci.plugins.workflow.cps.CpsBodyExecution$FailureAdapter.receive(CpsBodyExecution.java:361)
23:02:03  		at com.cloudbees.groovy.cps.impl.ThrowBlock$1.receive(ThrowBlock.java:68)
23:02:03  		at com.cloudbees.groovy.cps.impl.ConstantBlock.eval(ConstantBlock.java:21)
23:02:03  		at com.cloudbees.groovy.cps.Next.step(Next.java:83)
23:02:03  		at com.cloudbees.groovy.cps.Continuable$1.call(Continuable.java:174)
23:02:03  		at com.cloudbees.groovy.cps.Continuable$1.call(Continuable.java:163)
23:02:03  		at org.codehaus.groovy.runtime.GroovyCategorySupport$ThreadCategoryInfo.use(GroovyCategorySupport.java:129)
23:02:03  		at org.codehaus.groovy.runtime.GroovyCategorySupport.use(GroovyCategorySupport.java:268)
23:02:03  		at com.cloudbees.groovy.cps.Continuable.run0(Continuable.java:163)
23:02:03  		at org.jenkinsci.plugins.workflow.cps.SandboxContinuable.access$001(SandboxContinuable.java:18)
23:02:03  		at org.jenkinsci.plugins.workflow.cps.SandboxContinuable.run0(SandboxContinuable.java:51)
23:02:03  		at org.jenkinsci.plugins.workflow.cps.CpsThread.runNextChunk(CpsThread.java:185)
23:02:03  		at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.run(CpsThreadGroup.java:400)
23:02:03  		at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.access$400(CpsThreadGroup.java:96)
23:02:03  		at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup$2.call(CpsThreadGroup.java:312)
23:02:03  		at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup$2.call(CpsThreadGroup.java:276)
23:02:03  		at org.jenkinsci.plugins.workflow.cps.CpsVmExecutorService$2.call(CpsVmExecutorService.java:67)
23:02:03  Caused: java.io.NotSerializableException: java.util.Spliterators$1Adapter
23:02:03  	at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:926)
23:02:03  	at org.jboss.marshalling.river.RiverMarshaller.doWriteFields(RiverMarshaller.java:1082)
23:02:03  	at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:1040)
23:02:03  	at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:920)
23:02:03  	at org.jboss.marshalling.river.RiverMarshaller.doWriteFields(RiverMarshaller.java:1082)
23:02:03  	at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:1040)
23:02:03  	at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:920)
23:02:03  	at org.jboss.marshalling.river.RiverMarshaller.doWriteFields(RiverMarshaller.java:1082)
23:02:03  	at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:1040)
23:02:03  	at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:920)
23:02:03  	at org.jboss.marshalling.river.RiverMarshaller.doWriteFields(RiverMarshaller.java:1082)
23:02:03  	at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:1040)
23:02:03  	at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:1019)
23:02:03  	at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:920)
23:02:03  	at org.jboss.marshalling.river.RiverMarshaller.doWriteFields(RiverMarshaller.java:1082)
23:02:03  	at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:1040)
23:02:03  	at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:1019)
23:02:03  	at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:920)
23:02:03  	at org.jboss.marshalling.river.RiverMarshaller.doWriteFields(RiverMarshaller.java:1082)
23:02:03  	at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:1040)
23:02:03  	at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:1019)
23:02:03  	at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:920)
23:02:03  	at org.jboss.marshalling.river.RiverMarshaller.doWriteFields(RiverMarshaller.java:1082)
23:02:03  	at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:1040)
23:02:03  	at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:920)
23:02:03  	at org.jboss.marshalling.river.BlockMarshaller.doWriteObject(BlockMarshaller.java:65)
23:02:03  	at org.jboss.marshalling.river.BlockMarshaller.writeObject(BlockMarshaller.java:56)
23:02:03  	at org.jboss.marshalling.MarshallerObjectOutputStream.writeObjectOverride(MarshallerObjectOutputStream.java:50)
23:02:03  	at org.jboss.marshalling.river.RiverObjectOutputStream.writeObjectOverride(RiverObjectOutputStream.java:179)
23:02:03  	at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:344)
23:02:03  	at java.util.concurrent.ConcurrentSkipListMap.writeObject(ConcurrentSkipListMap.java:1437)
23:02:03  	at sun.reflect.GeneratedMethodAccessor291.invoke(Unknown Source)
23:02:03  	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
23:02:03  	at java.lang.reflect.Method.invoke(Method.java:498)
23:02:03  	at org.jboss.marshalling.reflect.JDKSpecific$SerMethods.callWriteObject(JDKSpecific.java:156)
23:02:03  	at org.jboss.marshalling.reflect.SerializableClass.callWriteObject(SerializableClass.java:191)
23:02:03  	at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:1028)
23:02:03  	at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:920)
23:02:03  	at org.jboss.marshalling.river.RiverMarshaller.doWriteFields(RiverMarshaller.java:1082)
23:02:03  	at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:1040)
23:02:03  	at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:920)
23:02:03  	at org.jboss.marshalling.AbstractObjectOutput.writeObject(AbstractObjectOutput.java:58)
23:02:03  	at org.jboss.marshalling.AbstractMarshaller.writeObject(AbstractMarshaller.java:111)
23:02:03  	at org.jenkinsci.plugins.workflow.support.pickles.serialization.RiverWriter.lambda$writeObject$0(RiverWriter.java:144)
23:02:03  	at org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.GroovySandbox.runInSandbox(GroovySandbox.java:237)
23:02:03  	at org.jenkinsci.plugins.workflow.support.pickles.serialization.RiverWriter.writeObject(RiverWriter.java:143)
23:02:03  	at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.saveProgram(CpsThreadGroup.java:553)
23:02:03  	at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.saveProgram(CpsThreadGroup.java:530)
23:02:03  	at org.jenkinsci.plugins.workflow.cps.CpsStepContext$3.onSuccess(CpsStepContext.java:555)
23:02:03  	at org.jenkinsci.plugins.workflow.cps.CpsStepContext$3.onSuccess(CpsStepContext.java:549)
23:02:03  	at org.jenkinsci.plugins.workflow.cps.CpsFlowExecution$4$1.run(CpsFlowExecution.java:917)
23:02:03  	at org.jenkinsci.plugins.workflow.cps.CpsVmExecutorService$1.run(CpsVmExecutorService.java:38)
23:02:03  	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
23:02:03  	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
23:02:03  	at hudson.remoting.SingleLaneExecutorService$1.run(SingleLaneExecutorService.java:136)
23:02:03  	at jenkins.util.ContextResettingExecutorService$1.run(ContextResettingExecutorService.java:28)
23:02:03  	at jenkins.security.ImpersonatingExecutorService$1.run(ImpersonatingExecutorService.java:59)
23:02:03  	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
23:02:03  	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
23:02:03  	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
23:02:03  	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
23:02:03  	at java.lang.Thread.run(Thread.java:748)

Run closures synchronously unless and until we cannot

Given an arbitrary method, perhaps in DefaultGroovyMethods but perhaps in some other (binary) library, which takes a (CPS-transformed) closure, the behavior is nonsensical:

[1, 2].whatever {println it}

will call whatever, and when that method calls Closure.call, the closure is run correctly…but once it returns, the whole call to whatever is suddenly terminated (with CpsCallableInvocation), and so the result is that the closure is only ever called once, and the overall return value is meaningless.

What we would prefer is that if the closure can run synchronously, we run it without CPS transformation and let the whatever method run to completion synchronously, so that basic calls like

def x = [1, 2].find {it %2 == 0}

will work. But if something inside the closure calls Continuable.suspend, then we need to notice that the call stack includes non-CPS methods, and we want to throw an error with a helpful message. Thus for example in a Workflow

[1, 2].each = {echo "found ${it}"}

would work (since EchoStep is synchronous and so tells DSL.invokeMethod to return null immediately), but

[1, 2].each = {sh "echo found ${it}"}

would throw an error (since DurableTaskStep is asynchronous and so tells DSL.invokeMethod to call Continuable.suspend).

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.