Scott Murphy Heiberg created GROOVY-12663:
---------------------------------------------
Summary: @PackedClosures packs dynamic closures whose calls
resolve against a closure object, calling the owner instead
Key: GROOVY-12663
URL: https://issues.apache.org/jira/browse/GROOVY-12663
Project: Groovy
Issue Type: Bug
Affects Versions: 6.0.0, 7.0.0-alpha-1
Reporter: Scott Murphy Heiberg
{code:groovy}
class C {
String toString() { 'C' }
@groovy.transform.PackedClosures Object m() { Closure outer = { -> { ->
toString() }() }; [outer(), outer.toString()] }
@groovy.transform.PackedClosures Object mem() { def c = { -> memoize() };
c() }
}
println new C().m()
new C().mem()
{code}
*Actual:* {{m()}} returns {{[C, C.$packed$closure$0@...]}} (the owner's
toString, not the outer closure's), and {{mem()}} throws
{{MissingMethodException: No signature of method: memoize for class: C}}. The
same happens for:
* other methods Closure declares: curry, dehydrate, rehydrate, asWritable,
trampoline, rightShift, and recursion through call or doCall; clone() throws
CloneNotSupportedException;
* the properties maximumNumberOfParameters and parameterTypes, which throw
MissingPropertyException;
* hashCode, equals, getClass and GDK methods such as with or is in a nested
closure.
*Expected:* the same results as without the annotation. Methods that Closure
declares resolve against the closure itself, and Object and GDK methods called
in a nested closure resolve against the enclosing closure.
Cause: in dynamic code the annotation is trusted, and the packing check only
rejects the pseudo-property calls such as getDelegate(). The hoisted body is a
method of the owner class, and a nested closure created in it gets the owner
instance as its owner, so these calls reach the owner. The @CompileStatic
counterpart is GROOVY-12660.
Verified on 6.0.0 and master.
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)