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

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

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

   Under `@CompileStatic`, an implicit-this call inside a lambda resolved to a 
method of `groovy.lang.Closure` even when the enclosing class declares a method 
of that name:
   
   ```groovy
   @CompileStatic class C {
       String getDelegate() { 'Cd' }
       String memoizeAtMost(int i) { 'C' + i }
       def m() {
           Supplier<Object> s = () -> getDelegate()
           Supplier<Object> t = () -> memoizeAtMost(2)
           [s.get(), t.get()]
       }
   }
   ```
   
   `new C().m()` returned the lambda's delegate and a memoized closure instead 
of `[Cd, C2]`, as 4.0 did (5.0.8 and 6.0.0 are affected). With `curry`, 
`rcurry` or `ncurry` declared in the class, it failed to compile as an 
ambiguous reference to `Closure#curry`. Since GROOVY-11386, 
`StaticTypeCheckingVisitor.visitMethodCallExpression` tries `Closure`'s methods 
before the owner and the delegate, for lambdas as well as closures.
   
   A lambda in statically compiled code follows Java semantics. The type 
checker now skips the `Closure` lookup in such a lambda when the delegate, the 
owner or the enclosing class has an applicable method (`isNativeLambda`, 
`hasReceiverMethod`). `Closure`'s methods remain the fallback, so 
`getThisObject()` still works in a lambda when the class does not declare it. A 
lambda in dynamic or `@TypeChecked` code is compiled as a closure, and at run 
time the closure's own methods come first, so the type checker keeps resolving 
to them there. Closures are unchanged, including a closure inside a lambda.
   
   Merges cleanly with #3183 (GROOVY-12662), which changes the line below the 
one this adds a condition to. A 5.0.x or 6.0.x backport needs a replacement for 
`isStaticDispatchScope()`, which is new in 7.0.0.
   
   ## Tests
   
   `LambdaTest.testLambdaCallsEnclosingClassMethodNamedLikeClosureMethod`, 
`testLambdaCallsEnclosingClassCurryMethod`, 
`testLambdaCallsEnclosingClassStaticMethodNamedLikeClosureMethod` and 
`testNestedLambdaAndClosureCallMethodNamedLikeClosureMethod` fail without the 
change. `testLambdaCallsClosureMethodWithoutEnclosingClassMethod` and 
`testDynamicLambdaCallsClosureMethodBeforeEnclosingClassMethod` cover the 
`Closure` fallback and the dynamic and `@TypeChecked` behaviour. 
`groovy.transform.stc.*`, `org.codehaus.groovy.classgen.asm.sc.*`, 
`org.codehaus.groovy.transform.traitx.*`, `gls.*` and `groovy.bugs.*` pass. The 
Checkstyle and CodeNarc gates pass.
   




> SC calls the Closure method instead of the enclosing class method of the same 
> name from a lambda
> ------------------------------------------------------------------------------------------------
>
>                 Key: GROOVY-12668
>                 URL: https://issues.apache.org/jira/browse/GROOVY-12668
>             Project: Groovy
>          Issue Type: Bug
>    Affects Versions: 5.0.8, 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 {
>     String getDelegate() { 'Cd' }
>     String memoizeAtMost(int i) { 'C' + i }
>     def m() {
>         Supplier<Object> s = () -> getDelegate()
>         Supplier<Object> t = () -> memoizeAtMost(2)
>         [s.get(), t.get()]
>     }
> }
> println new C().m()
> {code}
> *Actual* (5.0.8, 6.0.0, master): {{[C@6d1310f6, 
> org.codehaus.groovy.runtime.memoize.Memoize$MemoizeFunction@3228d990]}}. The 
> calls go to the lambda object's {{Closure.getDelegate()}} and 
> {{Closure.memoizeAtMost(int)}}. With {{curry(1)}}, {{rcurry}} or {{ncurry}} 
> declared in the class, compilation fails with "Reference to method is 
> ambiguous ... Closure#curry".
> *Expected* (as in 4.0.33): {{[Cd, C2]}}. The enclosing class's methods are 
> called, static ones included.
> Since GROOVY-11386, the type checker looks up an implicit-this call in a 
> closure or lambda on {{Closure}} before the owner and the delegate. A lambda 
> in statically compiled code follows Java semantics, so the enclosing class 
> should come first. A lambda in dynamic or @TypeChecked code is a closure at 
> run time, where the closure's own methods do come first.
> Verified: 5.0.8, 6.0.0 and master affected; 4.0.33 not affected.



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

Reply via email to