Paul King created GROOVY-12649:
----------------------------------

             Summary: SC: explicit spread over a Set or other non-List Iterable 
that declares the property casts each element to the receiver type
                 Key: GROOVY-12649
                 URL: https://issues.apache.org/jira/browse/GROOVY-12649
             Project: Groovy
          Issue Type: Bug
          Components: Static compilation
    Affects Versions: 6.0.0, 5.1.3, 4.0.33
            Reporter: Paul King


Description:

Under {{@CompileStatic}}, an explicit spread {{coll*.prop}} over a {{Set}} 
subclass, or over any other non-List {{Iterable}}, fails at runtime if the 
receiver's own class declares {{prop}} (as a field or a getter). The compiled 
code reads the receiver's property from each element instead, casting the 
element to the receiver type:

{code:groovy}
class Person { String name; Person(String n) { name = n } }
class PeopleSet extends LinkedHashSet<Person> { String name = 'the set' }

@groovy.transform.CompileStatic
def test() {
    def s = new PeopleSet()
    s << new Person('Alice') << new Person('Bob')
    assert s.name == 'the set'           // ok
    assert s*.name == ['Alice', 'Bob']   // GroovyCastException: Cannot cast 
object 'Person@...' with class 'Person' to class 'PeopleSet'
}
test()
{code}

Dynamic Groovy and {{@TypeChecked}} return {{[Alice, Bob]}}: an explicit spread 
always reads the elements.

||Receiver ({{x*.name}})||dynamic||CS ≤ 4.0.5||CS 4.0.24 → master||
|{{Set}} subclass declaring field {{name}}|[Alice, Bob]|[Alice, 
Bob]|GroovyCastException|
|{{Set}} subclass declaring {{getName()}}|[Alice, Bob]|[Alice, 
Bob]|GroovyCastException|
|{{Iterable}} (not a Collection) declaring field {{name}}|[Alice, Bob]|[Alice, 
Bob]|GroovyCastException|
|plain {{Set<Person>}}|[Alice, Bob]|[Alice, Bob]|[Alice, Bob]|

Seen on JDK 17 with 4.0.24, 4.0.33, 5.0.8, 5.1.3, 6.0.0 and master. It works on 
3.0.25 and 4.0.5, so this is a regression within the 4.0.x line. I haven't 
bisected it; 9e2ed767e3 (GROOVY-5568, GROOVY-10815, "SC: groovy method as 
property", first in 4.0.7) changed how SC compiles property access and is a 
likely candidate.

The {{List}} form of this ({{people*.name}} where a List subclass declares 
{{name}}, or gets it from an extension method) is addressed by GROOVY-12534 (PR 
#3058). Its spread skip in {{StaticTypeCheckingVisitor.existsProperty}} is 
limited to receivers implementing {{List}}, so the cases above still fail with 
that change applied. Widening that check to any receiver of an explicit spread 
may be enough, but I haven't tested it.

Related: GROOVY-6311 (resolved), where CS rejected spread over a {{Set}} at 
compile time.



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

Reply via email to