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]