[ 
https://issues.apache.org/jira/browse/GROOVY-12652?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18137330#comment-18137330
 ] 

ASF GitHub Bot commented on GROOVY-12652:
-----------------------------------------

codeconsole opened a new pull request, #3173:
URL: https://github.com/apache/groovy/pull/3173

   With closure packing enabled (`-Dgroovy.target.closure.pack=true` or 
`@PackedClosures`), a closure written in a constructor or in an instance 
initializer block was packed even when it escapes:
   
   ```groovy
   class P { P(List<Closure> s) { s << { x -> x } } }   // packed: 
PackedClosure$Fixed1
   class Q { Closure f; { f = { x -> x } } }             // packed: 
PackedClosure$Fixed1
   ```
   
   `ClosureWriter` asked `WriterController.getMethodNode()` for the enclosing 
method, and that is null while a constructor is being written. The escape gate, 
the serialization gate and the `@PackedClosures` mode lookup therefore saw 
nothing. This applies to dynamic, `@TypeChecked` and `@CompileStatic` code. 
Instance initializer blocks are inlined into each constructor by the Verifier, 
so they were affected as well. Under `@PackedClosures` the escaped closure then 
failed the packed adapter's runtime guard as soon as a delegate was set on it.
   
   `ClosureWriter.enclosingMethod()` now returns the constructor node when 
there is no method node, and the escape walk, the serialization walk and the 
mode lookup use it. `@PackedClosures` can now be placed on a constructor; its 
scope includes the initializer blocks inlined into it. A field initializer 
keeps its own decline reason.
   
   Seen in 6.0.0 too.
   
   Merging with #3171 (GROOVY-12650): `annotatedMode()` conflicts textually 
(resolve as `return annotatedMode(enclosingMethod(), 
controller.getClassNode());`), and #3171's marking would then also need to 
cover constructors and object initializer statements under `@CompileStatic`. 
Until both are in, the `@CompileStatic` rows for `<<` in a constructor and in 
an initializer block are left out of `constructorAndInitializerEscapesDecline`.
   
   ## Tests
   
   `PackedClosureBoundariesTest.constructorAndInitializerEscapesDecline` 
(field, property and append stores and a Serializable cast, in a constructor 
and in an initializer block, dynamic, `@TypeChecked` and `@CompileStatic`), 
`PackedClosuresTransformTest.escapingClosuresInConstructorsAndInitializersAreDeclined`
 and 
`PackedClosuresTransformTest.modeOnAConstructorGovernsItsBodyAndInitializers` 
fail without the change. 
`PackedClosureBoundariesTest.constructorAndInitializerLocalClosuresPack` checks 
that non-escaping closures still pack. The packing test classes, 
`org.codehaus.groovy.classgen.asm.sc.*` and `groovy.transform.stc.*` pass. The 
Checkstyle and CodeNarc gates pass.
   




> Closure packing ignores constructors and instance initializer blocks: 
> escaping closures are packed
> --------------------------------------------------------------------------------------------------
>
>                 Key: GROOVY-12652
>                 URL: https://issues.apache.org/jira/browse/GROOVY-12652
>             Project: Groovy
>          Issue Type: Bug
>    Affects Versions: 7.0.0-alpha-1, 6.0.0
>            Reporter: Scott Murphy Heiberg
>            Priority: Major
>
> With closure packing enabled ({{-Dgroovy.target.closure.pack=true}} or 
> {{@PackedClosures}}), a closure literal in a constructor or an instance 
> initializer block bypasses the escape gate, the serialization gate and the 
> per-method packing mode:
> {code:groovy}
> class P { P(List<Closure> s) { s << { x -> x } } }
> class Q { Closure f; { f = { x -> x } } }
> def s = []; new P(s)
> [s[0].getClass().name, new Q().f.getClass().name]
> {code}
> *Actual* (dynamic, @TypeChecked and @CompileStatic): 
> {{[org.codehaus.groovy.runtime.PackedClosure$Fixed1, 
> org.codehaus.groovy.runtime.PackedClosure$Fixed1]}}. Under 
> {{@PackedClosures}}, setting a delegate on the escaped closure then throws 
> UnsupportedOperationException. {{@PackedClosures}} cannot be placed on a 
> constructor ("not allowed on element CONSTRUCTOR").
> *Expected:* {{[P$_closure1, Q$_closure1]}}, the same result as for a method: 
> escaping closures keep their class.
> Cause: {{WriterController.getMethodNode()}} is null while a constructor is 
> written, so the escape walk, the serialization walk and the annotation lookup 
> in ClosureWriter see no enclosing method. Instance initializer blocks are 
> inlined into constructors by the Verifier, so they are affected too.



--
This message was sent by Atlassian Jira
(v10.3.26#10030026)

Reply via email to