[ 
https://issues.apache.org/jira/browse/GROOVY-12566?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Paul King updated GROOVY-12566:
-------------------------------
    Description: 
Description:

Under @CompileStatic, a property access through super inside a closure or a 
lambda compiles, but the closure or lambda class fails verification when it is 
loaded:

{code:groovy}
class C {
    String x = 'c'
}

@groovy.transform.CompileStatic
class D extends C {
    def test() {
        def c = { -> super.x }
        c()
    }
}
new D().test()
{code}

java.lang.VerifyError: Bad invokespecial instruction: current class isn't 
assignable to reference class.
  Location:
    D$_test_closure1.doCall()Ljava/lang/Object; @7: invokespecial

The closure reads its thisObject, casts it to D, and then calls C.getX() with 
invokespecial. The JVM only allows invokespecial on a superclass method from 
the subclass itself (D), not from the closure class. Calls to a superclass 
method from inside a closure don't have this problem.

The same failure occurs, with the same message, for:
 - a property with only a getter (String getY(), \{ -> super.y })
 - a boolean isX() getter (\{ -> super.flag })
 - a write (\{ -> super.x = 'v' })
 - a closure nested in a closure (\{ -> { -> super.x }() })

 - a lambda ((Supplier<String>) (() -> super.x))

These work:
 - super.x outside a closure or lambda
 - super.getX() and super.m() inside a closure
 - super.x in a closure in dynamic Groovy or under @TypeChecked

Expected: super.x in a closure or lambda behaves as super.getX() does there, 
calling the superclass's accessor (and the superclass's setter for a write).

Workaround: call the accessor explicitly, \{ -> super.getX() }, or \{ -> 
super.setX(v) } for a write.

  was:
Description:

Under @CompileStatic, a property access through super inside a closure or a 
lambda compiles, but the closure or lambda class fails verification when it is 
loaded:

class C {
    String x = 'c'
}
@groovy.transform.CompileStatic
class D extends C {
    def test() {
        def c = \{ -> super.x }
        c()
    }
}
new D().test()

java.lang.VerifyError: Bad invokespecial instruction: current class isn't 
assignable to reference class.
  Location:
    D$_test_closure1.doCall()Ljava/lang/Object; @7: invokespecial

The closure reads its thisObject, casts it to D, and then calls C.getX() with 
invokespecial. The JVM only allows invokespecial on a superclass method from 
the subclass itself (D), not from the closure class. Calls to a superclass 
method from inside a closure don't have this problem.

The same failure occurs, with the same message, for:
- a property with only a getter (String getY(), \{ -> super.y })
- a boolean isX() getter (\{ -> super.flag })
- a write (\{ -> super.x = 'v' })
- a closure nested in a closure (\{ -> { -> super.x }() })
- a lambda ((Supplier<String>) (() -> super.x))

These work:
- super.x outside a closure or lambda
- super.getX() and super.m() inside a closure
- super.x in a closure in dynamic Groovy or under @TypeChecked

Expected: super.x in a closure or lambda behaves as super.getX() does there, 
calling the superclass's accessor (and the superclass's setter for a write).

Workaround: call the accessor explicitly, \{ -> super.getX() }, or \{ -> 
super.setX(v) } for a write.


> SC: super.x inside a closure or lambda throws VerifyError
> ---------------------------------------------------------
>
>                 Key: GROOVY-12566
>                 URL: https://issues.apache.org/jira/browse/GROOVY-12566
>             Project: Groovy
>          Issue Type: Bug
>          Components: Static compilation
>    Affects Versions: 4.0.33, 5.1.3, 6.0.0
>            Reporter: Paul King
>            Priority: Major
>
> Description:
> Under @CompileStatic, a property access through super inside a closure or a 
> lambda compiles, but the closure or lambda class fails verification when it 
> is loaded:
> {code:groovy}
> class C {
>     String x = 'c'
> }
> @groovy.transform.CompileStatic
> class D extends C {
>     def test() {
>         def c = { -> super.x }
>         c()
>     }
> }
> new D().test()
> {code}
> java.lang.VerifyError: Bad invokespecial instruction: current class isn't 
> assignable to reference class.
>   Location:
>     D$_test_closure1.doCall()Ljava/lang/Object; @7: invokespecial
> The closure reads its thisObject, casts it to D, and then calls C.getX() with 
> invokespecial. The JVM only allows invokespecial on a superclass method from 
> the subclass itself (D), not from the closure class. Calls to a superclass 
> method from inside a closure don't have this problem.
> The same failure occurs, with the same message, for:
>  - a property with only a getter (String getY(), \{ -> super.y })
>  - a boolean isX() getter (\{ -> super.flag })
>  - a write (\{ -> super.x = 'v' })
>  - a closure nested in a closure (\{ -> { -> super.x }() })
>  - a lambda ((Supplier<String>) (() -> super.x))
> These work:
>  - super.x outside a closure or lambda
>  - super.getX() and super.m() inside a closure
>  - super.x in a closure in dynamic Groovy or under @TypeChecked
> Expected: super.x in a closure or lambda behaves as super.getX() does there, 
> calling the superclass's accessor (and the superclass's setter for a write).
> Workaround: call the accessor explicitly, \{ -> super.getX() }, or \{ -> 
> super.setX(v) } for a write.



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

Reply via email to