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

   In a statically compiled trait method, closures and lambdas got the static 
helper class where the trait instance, or the implementing class in a static 
method, is expected:
   
   ```groovy
   @CompileStatic
   trait T {
       String helper() { 'helper' }
       Object own() { def c = { owner }; c() }                                  
 // GroovyCastException to T$Trait$Helper
       String viaThis() { def c = { this.helper() }; c() }                      
 // ClassCastException: Class to T$Trait$Helper
       String viaLambda() { Supplier<String> s = () -> helper(); s.get() }      
 // ClassCastException: Class to T
       static Closure<String> f = { 'f' }
       static String callF() { f() }                                            
 // MissingMethodException: T__f$get
   }
   ```
   
   Five commits:
   
   - The type checker types the this object of a closure in a trait instance 
method or instance field initializer, and its owner and delegate when it is not 
nested in another closure, as the trait (with its `@SelfType` types), since the 
trait transformation rehydrates the closure to `$self`. `owner`, `thisObject`, 
`delegate` without `@DelegatesTo`, `getOwner()` and `getThisObject()` failed 
with a GroovyCastException, under `@TypeChecked` too.
   - A closure in a lambda of a trait method gets the trait instance: a lambda 
that uses instance state and contains a closure is given `$self` (or 
`$static$self`) as its owner and this object instead of the helper class. In 
any class, a lambda whose closure reads only `owner` now captures, so the 
closure's owner is the lambda and not the lambda's class.
   - `this.m()` in a closure or lambda of a trait method calls `m` on the trait 
instance, as `this` alone already resolves. It called the helper class in all 
three modes: a ClassCastException under `@CompileStatic`, a 
MissingMethodException for a method with arguments, a `@SelfType` method or an 
abstract method in dynamic and `@TypeChecked` code, and the helper's 
`toString()` and `getClass()`.
   - Any lambda in a trait helper method that uses instance state gets `$self` 
as its owner and this object, so `() -> helper()` works.
   - `f()` on a static closure field of a trait reads the field of the 
implementing class, as `f.call()` and dynamic code do, instead of going through 
the trait's static accessor.
   
   ## Tests
   
   `TraitWithClosureOrLambda.testOwnerAndThisObjectOfTraitClosure`, 
`testClosureInTraitLambda`, `testExplicitThisMethodCallInTraitClosure` and 
`testStaticClosureFieldCalledAsMethod`, and 
`LambdaTest.testOwnerOfClosureInLambda`, fail without the change. 12,903 tests 
in the `groovy`, `gls`, `bugs`, STC/SC and `org.codehaus.groovy.transform` 
packages pass, and the Checkstyle and CodeNarc gates pass.
   
   Seen in 4.0.33, 5.0.8 and 6.0.0 (the static closure field is a type-checking 
error there before 6.0.0).
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to