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

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

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

   An implicit-this call from an inner class to a method of an enclosing class 
now runs on the innermost enclosing instance whose class has the method, in 
dynamic and statically compiled code, inside and outside closures and lambdas.
   
   Before, a closure in a field initializer of an inner class of a 
`@CompileStatic` class failed in each `@CompileDynamic` constructor:
   
   ```groovy
   @CompileStatic
   class Outer {
       String pub() { 'pub' }
       class Inner {
           String v = { -> pub() }()
           @CompileDynamic Inner() {}   // GroovyCastException: Outer$Inner 
cannot be cast to Outer
       }
   }
   ```
   
   The static compiler gives the call a method target, and the dynamic 
invocation writer, which writes the initializer into the `@CompileDynamic` 
constructor, kept the closure's this object as the receiver. Lambdas, nested 
closures, private methods, interface default methods and trait methods failed 
the same way, as did a `@CompileStatic` inner class of a dynamic class.
   
   A method inherited by an intermediate enclosing class (`Outer > Mid extends 
Base > Inner` calling `base()`) failed verification under `@CompileStatic`, or 
ran on the outermost instance when that class inherits the method too. Both 
invocation writers loaded `DeclaringClass.this`; they now use the innermost 
enclosing instance whose class extends or implements the declaring class, as 
the static writer already did inside closures.
   
   Tests: `InnerClassTest.testUsageOfOuterMethod11` and 
`testUsageOfOuterMethod12` (dynamic, `@TypeChecked` and `@CompileStatic`). 
`testUsageOfOuterMethod11` and the `@CompileStatic` case of 
`testUsageOfOuterMethod12` fail without the change; the other two cases guard 
the dynamic and type-checked paths. The `groovy`, `gls`, `bugs` and 
`org.codehaus.groovy` packages pass (15,499 tests). The Checkstyle and CodeNarc 
gates pass.
   
   Seen in 4.0.33, 5.0.8 and 6.0.0.
   




> An outer class method called from an inner class runs on the wrong enclosing 
> instance
> -------------------------------------------------------------------------------------
>
>                 Key: GROOVY-12574
>                 URL: https://issues.apache.org/jira/browse/GROOVY-12574
>             Project: Groovy
>          Issue Type: Bug
>          Components: Compiler, Static compilation
>    Affects Versions: 4.0.33, 5.0.8, 6.0.0
>            Reporter: Scott Murphy Heiberg
>            Priority: Major
>
> An implicit-this call from an inner class to a method of an enclosing class 
> can run on the wrong instance.
> A closure in a field initializer of an inner class of a {{@CompileStatic}} 
> class fails in each {{@CompileDynamic}} constructor:
> {code:groovy}
> import groovy.transform.*
> @CompileStatic
> class Outer {
>     String pub() { 'pub' }
>     class Inner {
>         String v = { -> pub() }()
>         @CompileDynamic Inner() {}
>     }
>     String test() { new Inner().v }
> }
> new Outer().test() // GroovyCastException: Cannot cast object 
> 'Outer$Inner@...' with class 'Outer$Inner' to class 'Outer'
> {code}
> The static compiler gives the call a method target, and the dynamic 
> invocation writer, which writes the initializer into the {{@CompileDynamic}} 
> constructor, keeps the closure's this object as the receiver. Lambdas, nested 
> closures, private methods, interface default methods and trait methods fail 
> the same way, as does a {{@CompileStatic}} inner class of a dynamic class.
> A method that an intermediate enclosing class inherits is called on the wrong 
> instance:
> {code:groovy}
> import groovy.transform.*
> class Base { String base() { 'base' } }
> @CompileStatic
> class Outer {
>     class Mid extends Base {
>         class Inner { String m() { base() } }
>     }
>     String test() { def mid = new Mid(); new Mid.Inner(mid).m() }
> }
> new Outer().test() // VerifyError: Bad type on operand stack ... 
> Outer$Mid$Inner.m()
> {code}
> Both writers load {{DeclaringClass.this}}, which walks the enclosing 
> instances until it reaches the declaring class itself. When {{Outer}} extends 
> {{Base}} too, {{base()}} runs on the {{Outer}} instance; dynamic Groovy and 
> Java use the {{Mid}} instance. Property reads through an inherited getter 
> behave the same.
> Expected: the innermost enclosing instance whose class extends or implements 
> the declaring class, as the static writer already uses inside closures.



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

Reply via email to