[ 
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)

Reply via email to