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

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

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

   In trait code, a property referenced from a closure ignored the closure's 
delegate:
   
   ```groovy
   trait T {
       def cnt = 1
       def m() { [cnt: 42].with { cnt } }
   }
   class C implements T {}
   assert new C().m() == 42 // was 1
   ```
   
   The same code in a class returns 42, in dynamic, `@TypeChecked` and 
`@CompileStatic` code. 4.0.33, 5.0.8 and 6.0.0 return 1. 
`TraitReceiverTransformer` rewrote the reference to a direct access on the 
implementing instance (`$self.cnt` or the field-helper getter or setter) before 
the closure's resolve strategy could apply. Assignments (`cnt = 5`) wrote the 
trait property instead of the delegate's. An accessor-only property (`def 
getCnt()`) failed with `ReadOnlyPropertyException` on assignment.
   
   `TraitReceiverTransformer` now leaves a reference to an instance property of 
the trait unrewritten inside a closure, whether the property is declared or 
backed by an accessor. The closure is rehydrated with the implementing instance 
as owner, so the reference resolves through the delegate and owner as for a 
class, and the owner fallback uses the property's accessors. Lambdas and static 
trait methods keep the existing rewrite. A statically compiled lambda has no 
delegate and is not rehydrated. In a static method, the owner fallback would 
bind to the trait interface's static accessor.
   
   Two side effects now match classes too. `[1].each { x++ }` and `x += 2` on 
an instance trait property used to lose the update (under `@CompileStatic`, 
`+=` threw `GroovyCastException`). A closure now reads the property through its 
getter, so an overriding getter in the implementing class is used.
   
   ## Tests
   
   `TraitASTTransformationTest.testTraitPropertyInDelegateFirstClosure`, 
`testTraitAccessorPropertyInDelegateFirstClosure`, 
`testTraitPropertyInClosureFallsBackToOwner` and 
`testTraitPropertyInClosureUsesAccessor` each run in dynamic, `@TypeChecked` 
and `@CompileStatic` mode, and all fail without the change. 
`org.codehaus.groovy.transform.traitx.*`, `groovy.transform.stc.*`, 
`org.codehaus.groovy.classgen.asm.sc.*`, `gls.*`, `bugs.*` and 
`groovy.ThisAndSuperTest` pass. The Checkstyle and CodeNarc gates pass.
   




> A trait property referenced from a closure ignores the closure's delegate and 
> resolve strategy
> ----------------------------------------------------------------------------------------------
>
>                 Key: GROOVY-12598
>                 URL: https://issues.apache.org/jira/browse/GROOVY-12598
>             Project: Groovy
>          Issue Type: Bug
>    Affects Versions: 4.0.33, 5.0.8, 6.0.0
>            Reporter: Scott Murphy Heiberg
>            Priority: Major
>
> {code:groovy}
> trait T {
>     def cnt = 1
>     def m() { [cnt: 42].with { cnt } }
> }
> class C implements T {}
> assert new C().m() == 42
> {code}
> Actual: 1. The closure reads the trait's own property, in dynamic, 
> @TypeChecked and @CompileStatic code. Assigning, as in a with closure that 
> does cnt = 5, writes the trait property instead of the map. An accessor-only 
> property (a getCnt method) behaves the same way, and assigning to it throws 
> ReadOnlyPropertyException. A method parameter annotated with DelegatesTo and 
> DELEGATE_FIRST behaves the same as with.
> Expected: 42, as for the same code in a class. The delegate is checked first 
> under DELEGATE_FIRST, and the property of the implementing instance is used 
> only when the delegate does not have one.
> Cause: TraitReceiverTransformer rewrites a reference to a trait field or 
> property into a direct access on the implementing instance or a field-helper 
> call, even inside a closure. The closure's resolve strategy is therefore 
> never consulted.
> Seen in 4.0.33, 5.0.8 and 6.0.0.



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

Reply via email to