[
https://issues.apache.org/jira/browse/GROOVY-12624?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18135672#comment-18135672
]
ASF GitHub Bot commented on GROOVY-12624:
-----------------------------------------
codeconsole opened a new pull request, #3150:
URL: https://github.com/apache/groovy/pull/3150
In a trait instance method, `TraitReceiverTransformer` rewrites a closure's
call to a static or private trait method as `T$Trait$Helper.m($self or (Class)
$self.getClass(), x)`. Both synthesized calls kept the default implicit-this
flag, so static compilation resolved them against the closure's delegate:
```groovy
@groovy.transform.CompileStatic
trait V {
static String who() { this.simpleName }
def m() { new Object().with { who() } }
}
class E implements V {}
assert new E().m() == 'E' // was 'Object': getDelegate().getClass()
```
```groovy
class Dg { String who(Class c) { 'delegate' } }
@groovy.transform.CompileStatic
trait T {
static String who() { this.simpleName }
def m() { new Dg().with { who() } }
}
class C implements T {}
assert new C().m() == 'C' // was 'delegate': Dg.who(Class) got the added
self argument
```
Dynamic Groovy and `@TypeChecked` return `'E'` and `'C'`.
`TraitReceiverTransformer` now builds `$self.getClass()` in one place,
`selfGetClass()`, as an explicit call on `$self`, as static field access
already did. In a closure, the rewritten call on the trait helper is also
explicit. Whether a delegate method of the same signature should win over a
private or static trait method is #3138 (GROOVY-12611); the tests here use a
delegate without such a method, so they hold either way.
## Tests
These `TraitWithClosureOrLambda` tests fail without the change:
`testInvokeTraitStaticMethodFromDelegateClosureInInstanceMethod`,
`testInvokeSuperTraitStaticMethodFromDelegateClosureInInstanceMethod` and
`testInvokeTraitMethodFromDelegateClosureNotOnDelegateWithSelfParameter`. They
cover dynamic, `@TypeChecked` and `@CompileStatic` code, explicit and implicit
`this`, a lambda, a `@Virtual` static, a super-trait static, a private method
and two implementing classes.
`testReadTraitStaticFieldFromDelegateClosureInInstanceMethod` covers static
field and property access from a delegate closure. The
`org.codehaus.groovy.transform.traitx`, `groovy.transform.stc` and
`org.codehaus.groovy.classgen.asm.sc` tests, `groovy.ThisAndSuperTest`, and the
`*Trait*` and `bugs` tests pass. The Checkstyle and CodeNarc gates pass.
> SC resolves calls that the trait transformation adds in a closure against the
> closure's delegate
> ------------------------------------------------------------------------------------------------
>
> Key: GROOVY-12624
> URL: https://issues.apache.org/jira/browse/GROOVY-12624
> Project: Groovy
> Issue Type: Bug
> Affects Versions: 6.0.0
> Reporter: Scott Murphy Heiberg
> Priority: Major
>
> {code:groovy}
> @groovy.transform.CompileStatic
> trait V {
> static String who() { this.simpleName }
> def m() { new Object().with { who() } }
> }
> class E implements V {}
> assert new E().m() == 'E'
> class Dg {
> String who(Class c) { 'delegate' }
> }
> @groovy.transform.CompileStatic
> trait T {
> static String who() { this.simpleName }
> def m() { new Dg().with { who() } }
> }
> class C implements T {}
> assert new C().m() == 'C'
> {code}
> Actual: under static compilation the first m() returns 'Object' (the
> delegate's class), also when who is declared in a super trait or called as
> this.who(). The second m() returns 'delegate': it calls Dg.who(Class) with
> the self argument that the trait transformation added.
> Expected: 'E' and 'C', as dynamic Groovy and @TypeChecked return.
> Cause: TraitReceiverTransformer rewrites the call to a trait helper call with
> the receiver class as first argument. Both the outer helper call and the
> inner getClass() call keep the default implicit-this flag, so the static
> compiler resolves them against the closure's delegate.
> Seen on master; 5.0.8 and 6.0.0 reported the same.
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)