Paul King created GROOVY-12637:
----------------------------------
Summary: CS: an Object method such as toString() or hashCode()
called without a receiver inside an inner class (named or anonymous) is
resolved to the *outer* class's override, instead of the method the inner class
inherits
Key: GROOVY-12637
URL: https://issues.apache.org/jira/browse/GROOVY-12637
Project: Groovy
Issue Type: Bug
Reporter: Paul King
Under {{@CompileStatic}}, an {{Object}} method such as {{toString()}} or
{{hashCode()}} called without a receiver inside an inner class (named or
anonymous) is resolved to the *outer* class's override, instead of the method
the inner class inherits. Dynamic and {{@TypeChecked}} code call the inner
class's method, as Java does.
h3. Example
{code:groovy}
@groovy.transform.CompileStatic
class C {
String toString() { 'C' }
def m() {
new Object() {
def x() { toString() }
}.x()
}
}
assert new C().m() != 'C' // fails: the outer class's toString() is called
{code}
Results:
||Case||dynamic||{{@TypeChecked}}||{{@CompileStatic}}||
|anonymous inner class, {{toString()}}|anonymous object|anonymous
object|{{'C'}}|
|named inner class, {{toString()}}|inner object|inner object|{{'C'}}|
|anonymous inner class, {{hashCode()}} (outer returns 7)|identity hash|identity
hash|{{7}}|
|closure inside an anonymous inner class, {{toString()}}|anonymous
object|anonymous object|the enclosing closure's {{toString()}}|
When the inner class declares the method itself, the right method is called.
h3. Analysis
The type checker's method lookup on the inner class returns the outer class's
{{toString()}} ({{C.toString()}} for receiver {{C$1}}) ahead of the
{{Object.toString()}} that {{C$1}} inherits. The static invocation writer then
reaches the outer instance through {{this$0}}. When the anonymous class is
created inside a closure, {{this$0}} is that closure, which explains the last
row.
The lookup should only fall back to outer-class methods when the inner class
has no applicable method, inherited ones included.
h3. Notes
* Observed on master (7.0.0-SNAPSHOT, after GROOVY-12576). Not checked on 5.x
or 6.0.x.
* Not caused by GROOVY-12576, which only changed how closures resolve these
methods. The first three rows involve no closures.
* {{equals()}} was not tested but presumably behaves the same.
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)