[
https://issues.apache.org/jira/browse/GROOVY-12574?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Scott Murphy Heiberg updated GROOVY-12574:
------------------------------------------
Description:
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.
PR: https://github.com/apache/groovy/pull/3106
was:
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.
> 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.
> PR: https://github.com/apache/groovy/pull/3106
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)