[
https://issues.apache.org/jira/browse/GROOVY-12650?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18137318#comment-18137318
]
ASF GitHub Bot commented on GROOVY-12650:
-----------------------------------------
codeconsole opened a new pull request, #3171:
URL: https://github.com/apache/groovy/pull/3171
Closure packing (GEP-27) should decline a closure literal that visibly
escapes its method: stored to a field, property or index, appended with `<<`,
returned, or placed in a collection literal. Under `@CompileStatic` it packed
two of these shapes:
```groovy
class H { Closure value }
@groovy.transform.CompileStatic def m() {
List<Closure> l = []
l << { 1 } // packed
def h = new H()
h.value = { 2 } // packed
[l[0].getClass().name, h.value.getClass().name]
}
```
With `-Dgroovy.target.closure.pack=true` this returns two
`PackedClosure$FixedIt`; dynamic Groovy and `@TypeChecked` return two closure
classes. The escape walk in `ClosureWriter` runs at class generation. Under
static compilation, `BinaryExpressionTransformer` has already turned the `<<`
into a `leftShift` call and the store into a setter call, and the walk only
recognises the binary-expression forms.
`StaticCompilationTransformer` now calls
`ClosureWriter.markEscapingClosures` before it transforms each method body.
This runs the same escape walk over the untransformed code and marks the
escaping closure literals. The escape gate honours the mark, then still runs
its own walk at class generation, which also sees the implicit `return`s the
Verifier adds later. The marking only runs when the flag or a non-DISABLED
`@PackedClosures` requests packing. Because declines go through the same gate,
WARN/STRICT report these closures with the usual "escapes its method" reason.
## Tests
`PackedClosuresTransformTest.escapingClosuresAreDeclinedTheSameUnderCompileStatic`,
`compileStaticReportsAnEscapeHiddenByARewrite` and
`compileStaticFlagPathDeclinesAnEscapeHiddenByARewrite` fail without the
change. The first runs every escape shape under dynamic, `@TypeChecked` and
`@CompileStatic`, and checks that an explicit `leftShift(...)` call and an
owner-local closure still pack. The closure-packing test classes,
`org.codehaus.groovy.classgen.asm.sc.*` and `groovy.transform.stc.*` pass. The
Checkstyle and CodeNarc gates pass.
> Closure packing packs closures that escape via << or a setter store under
> @CompileStatic
> ----------------------------------------------------------------------------------------
>
> Key: GROOVY-12650
> URL: https://issues.apache.org/jira/browse/GROOVY-12650
> Project: Groovy
> Issue Type: Bug
> Affects Versions: 7.0.0-alpha-1
> Reporter: Scott Murphy Heiberg
> Priority: Major
>
> {code:groovy}
> // -Dgroovy.target.closure.pack=true, or @PackedClosures on the class/method
> class H { Closure value }
> @groovy.transform.CompileStatic def m() {
> List<Closure> l = []
> l << { 1 }
> def h = new H()
> h.value = { 2 }
> [l[0].getClass().name, h.value.getClass().name]
> }
> m()
> {code}
> *Actual:* {{[org.codehaus.groovy.runtime.PackedClosure$FixedIt,
> org.codehaus.groovy.runtime.PackedClosure$FixedIt]}}. Both escaping closures
> are packed.
> *Expected:* {{[Script1$_m_closure1, Script1$_m_closure2]}}. Both closures
> escape the method and should be declined from packing, as they are in dynamic
> Groovy and under {{@TypeChecked}}.
> The packing escape check ({{ClosureWriter.collectEscapingClosures}}) walks
> the method body at class generation. Under static compilation,
> {{BinaryExpressionTransformer}} has already rewritten the {{<<}} into a
> {{leftShift}} call and the setter-backed property store into a setter call,
> so the walk no longer recognises them as escapes. Other escape shapes
> (subscript, map and field stores, named constructor arguments, stores to a
> property of the same class) are already declined under {{@CompileStatic}}.
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)