[
https://issues.apache.org/jira/browse/GROOVY-12576?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18135468#comment-18135468
]
ASF GitHub Bot commented on GROOVY-12576:
-----------------------------------------
paulk-asert commented on PR #3102:
URL: https://github.com/apache/groovy/pull/3102#issuecomment-6535519149
Thanks, this looks good overall. Two things before merge:
**1. Closures using `TO_SELF` no longer compile.** A closure whose resolve
strategy is `TO_SELF` can't call `toString()` any more:
class C {
String toString() { 'C' }
static Object run(@DelegatesTo(value=String,
strategy=Closure.TO_SELF) Closure c) {
c.resolveStrategy = Closure.TO_SELF; c.delegate = 'd'; c()
}
Object m() { run { -> toString() } }
}
On master it compiles, and both dynamic and `@CompileStatic` return the
closure's own `toString()`. With this PR, both `@CompileStatic` and
`@TypeChecked` fail with `[Static type checking] - Cannot find matching method
C#toString()`. With `TO_SELF` only the closure itself is searched, and its
`Object` methods have now been removed from that search. Could the `removeIf`
be skipped when the strategy is `TO_SELF`? A test for it would be good too.
**2. The 4.0 claim in the description.** Results for `toString()` called
inside a closure:
| | 4.0.32 | 5.0.6 | master | this PR |
|---|---|---|---|---|
| dynamic | closure | closure | owner | owner |
| `@CompileStatic` | owner | closure | closure | owner |
Dynamic code only started going to the delegate or owner with GROOVY-11858,
which is on master and 6.0.x but not on 5.1.x. So in 4.0, SC and dynamic
disagreed, and in 5.x they agree. This PR lines SC up with 6.0+ dynamic
behaviour.
For that reason I'd backport to 6.0.x (with the `TO_SELF` fix) but not to
5.1.x. On 5.1.x, the `@TypeChecked` variant of
`testClosureObjectMethodPrecedence` fails, because it runs dynamically, while
the statically compiled one passes. Backporting would split SC from dynamic
there.
Minor and optional: with `rehydrate(null, owner, null)`, dynamic code calls
the owner's method, while this PR falls back to the closure. Trying
`getOwner()` before the closure would match dynamic in that case. Not a blocker.
> 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
> Assignee: Daniel Sun
> 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.
> PR: https://github.com/apache/groovy/pull/3102
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)