[
https://issues.apache.org/jira/browse/GROOVY-12576?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18134526#comment-18134526
]
ASF GitHub Bot commented on GROOVY-12576:
-----------------------------------------
codeconsole opened a new pull request, #3102:
URL: https://github.com/apache/groovy/pull/3102
Under `@CompileStatic`, `toString()`, `hashCode()`, `equals()` and
`getClass()` called without a receiver inside a closure or lambda now go to the
delegate or the owner according to the resolve strategy, as they do in dynamic
and `@TypeChecked` code and as they did in 4.0. So `new StringBuilder().with {
append('w'); toString() }` returns `'w'`, not the closure's `toString()`. In a
lambda, `toString()` is the enclosing instance's, as in Java. In a static
method it is the class's. Methods that `Closure` declares, such as
`getDelegate()` or `getMetaClass()`, still resolve against the closure.
The type checker looked up the methods of `Closure` before the delegate and
the owner, and that lookup also returned the methods `Closure` inherits from
`Object`. It now leaves those out, and the static invocation writer calls a
method of `Object` that was resolved against the owner on the closure's this
object, as it already did for other owner methods.
A closure returned by `dehydrate()` has no this object. If it calls one of
these methods without a receiver, it uses its own method, as before; the writer
loads the this object and falls back to the closure when it is `null`.
Tests: `ClosuresSTCTest.testClosureObjectMethodPrecedence` (also run
statically compiled by `ClosuresStaticCompileTest`) and
`ClosuresStaticCompileTest.testObjectMethodsInClosureWithoutThisObject`, which
fail without the change. The `groovy`, `gls`, `bugs` and `org.codehaus.groovy`
packages pass (15,513 tests), apart from `bugs.Groovy12363`, which also fails
on master when it runs after `bugs.Groovy12142` in the same JVM (GROOVY-12580
fixes it). The Checkstyle and CodeNarc gates pass.
A regression in 5.0.0: 4.0.33 is correct, 5.0.8 and 6.0.0 are not.
> SC: toString(), hashCode(), equals() and getClass() in a closure ignore the
> delegate and the owner
> --------------------------------------------------------------------------------------------------
>
> Key: GROOVY-12576
> URL: https://issues.apache.org/jira/browse/GROOVY-12576
> Project: Groovy
> Issue Type: Bug
> Components: Static compilation
> Affects Versions: 5.0.8, 6.0.0
> Reporter: Scott Murphy Heiberg
> Priority: Major
>
> Under {{@CompileStatic}}, an implicit-this call to a method of {{Object}} in
> a closure or lambda is made on the closure itself:
> {code:groovy}
> @groovy.transform.CompileStatic
> class C {
> String m() { new StringBuilder().with { append('w'); toString() } }
> }
> assert new C().m() == 'w' // C$_m_closure1@1b2c3d4
> {code}
> 4.0.33 returns {{'w'}}. The type checker looks up the methods of {{Closure}}
> before the delegate and the owner, and that lookup also returns the methods
> {{Closure}} inherits from {{Object}}. With {{with}}, {{tap}}, {{identity}} or
> a {{@DelegatesTo(strategy = DELEGATE_FIRST)}} method this ignores the
> delegate; in a plain closure it ignores the owner, and in a lambda the
> enclosing instance, which Java and dynamic Groovy both use. This happens in
> methods, constructors, field initializers and static initializers.
> Dynamic Groovy tries the closure first only for methods that {{Closure}} or
> {{GroovyObject}} declare; a method the closure inherits from elsewhere goes
> to the delegate or the owner according to the resolve strategy. Expected: the
> same under static compilation. Methods declared by {{Closure}}, such as
> {{getDelegate()}}, still resolve against the closure, and a closure without a
> this object (from {{dehydrate()}}) uses its own method.
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)