[
https://issues.apache.org/jira/browse/GROOVY-12672?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18137446#comment-18137446
]
ASF GitHub Bot commented on GROOVY-12672:
-----------------------------------------
codeconsole opened a new pull request, #3193:
URL: https://github.com/apache/groovy/pull/3193
Under `@CompileStatic`, a lambda that reads a closure property it does not
get from the enclosing class throws at run time:
```groovy
@CompileStatic
class C {
def m() { Supplier<Object> s = () -> delegate; s.get() }
}
new C().m() // ClassCastException: class java.lang.Class cannot be cast to
class C$_m_lambda1
```
The same happens for `owner`, `maximumNumberOfParameters`,
`resolveStrategy`, `parameterTypes`, `directive` and `metaClass`, including in
static methods, nested lambdas and lambdas inside closures; assigning
`resolveStrategy` fails too. 6.0.0 is affected; 4.0 and 5.0 do not throw.
Since GROOVY-11905, a lambda that does not touch the enclosing instance gets
a static `doCall`. `StaticTypesLambdaAnalyzer` counted only `this`, `super` and
`thisObject` as such access. The other closure properties are dynamic variables
that the generated code reads from the lambda itself, and in a static `doCall`
that receiver is the enclosing `Class`. The analyzer now treats every dynamic
variable in the body as access to the lambda, as `thisObject` already was.
The lambda keeps its instance and has the enclosing object as owner and
delegate, which is the type the checker infers for them and what dynamic Groovy
returns. This differs from 4.0 and 5.0, where such a lambda got the enclosing
`Class` as owner and delegate unless it touched an instance member, so
`Supplier<C> s = () -> owner` returned a `Class`. In a static method they are
the class, as before.
## Tests
`LambdaTest.testAccessingClosureProperties1` to `5` fail without the change:
four with ClassCastException and one with IncompatibleClassChangeError. They
cover dynamic, `@TypeChecked` and `@CompileStatic`; instance and static
methods; capturing lambdas; nested lambdas; a lambda in a closure; and
assignment to `resolveStrategy`. `groovy.transform.stc.*`,
`org.codehaus.groovy.classgen.asm.sc.*`,
`org.codehaus.groovy.transform.traitx.*`, `gls.innerClass.*`,
`groovy.ThisAndSuperTest` and the packed-closure tests pass. The Checkstyle and
CodeNarc gates pass.
> SC: a lambda that reads delegate, owner, resolveStrategy or
> maximumNumberOfParameters throws ClassCastException
> ---------------------------------------------------------------------------------------------------------------
>
> Key: GROOVY-12672
> URL: https://issues.apache.org/jira/browse/GROOVY-12672
> Project: Groovy
> Issue Type: Bug
> Affects Versions: 7.0.0-alpha-1, 6.0.0
> Reporter: Scott Murphy Heiberg
> Priority: Major
>
> {code:groovy}
> import groovy.transform.CompileStatic
> import java.util.function.Supplier
> @CompileStatic
> class C {
> def m() {
> Supplier<Object> s = () -> delegate
> s.get()
> }
> }
> assert new C().m() instanceof C
> {code}
> *Actual:* {{java.lang.ClassCastException: class java.lang.Class cannot be
> cast to class C$_m_lambda1}}. The same happens for {{owner}},
> {{maximumNumberOfParameters}}, {{resolveStrategy}}, {{parameterTypes}},
> {{directive}} and {{metaClass}}, in instance and static methods, in nested
> lambdas and in a lambda inside a closure. Assigning {{resolveStrategy}} fails
> with {{NoSuchMethodException: java.lang.Class.setProperty}}.
> *Expected:* the property is read from the lambda. {{delegate}} and {{owner}}
> are the enclosing object, as for {{thisObject}} and as the type checker
> infers; in a static method they are the class. 4.0.33 and 5.0.8 do not throw;
> they return the class for {{delegate}} and {{owner}}.
> Cause: since GROOVY-11905, a lambda that does not touch the enclosing
> instance gets a static {{doCall}}. Only {{this}}, {{super}} and
> {{thisObject}} counted as such access ({{StaticTypesLambdaAnalyzer}}), so a
> closure property is read from the enclosing Class instead of the lambda.
> Verified: 6.0.0 and master affected; 4.0.33 and 5.0.8 not affected.
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)