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

Daniel Sun reassigned GROOVY-12536:
-----------------------------------

    Assignee: Daniel Sun

> SC: a lambda or method reference taking a String throws ClassCastException 
> for a GString element of a List<String>
> ------------------------------------------------------------------------------------------------------------------
>
>                 Key: GROOVY-12536
>                 URL: https://issues.apache.org/jira/browse/GROOVY-12536
>             Project: Groovy
>          Issue Type: Bug
>            Reporter: Paul King
>            Assignee: Daniel Sun
>            Priority: Major
>
> A {{List<String>}} filled by dynamic code may hold {{GString}} elements, 
> because generic types are not checked at runtime. In statically compiled 
> code, Groovy converts such an element to a {{String}} wherever a {{String}} 
> is required. That includes assignments, arguments, calls to {{String}}-only 
> methods, and closure parameters ({{list.collect { it.toUpperCase() }}}). 
> Native lambdas and method references are the exception: they throw a 
> {{ClassCastException}}, even when the body only uses {{CharSequence}} or 
> {{Object}} members:
> {code:groovy}
> import groovy.transform.CompileStatic
> @CompileStatic
> class L {
>     static a(List<String> l) { l.stream().map(s -> 
> s.toUpperCase()).findFirst().get() }
>     static b(List<String> l) { 
> l.stream().map(String::toUpperCase).findFirst().get() }
>     static c(List<String> l) { l.stream().map(s -> 
> s.length()).findFirst().get() }
>     static d(List<String> l) { l.stream().map(s -> 
> s.toString()).findFirst().get() }
>     static e(List<String> l) { l.stream().map { it.toUpperCase() 
> }.findFirst().get() }
> }
> def n = 'ab'
> List<String> gs = ["$n"]   // element is a GString
> {code}
> ||Call||@CompileStatic (4.0.29, 5.0.5, 6.0.0, master)||Dynamic||
> |{{a}}: {{s -> s.toUpperCase()}}|ClassCastException|{{AB}}|
> |{{b}}: {{String::toUpperCase}}|ClassCastException|MissingMethodException|
> |{{c}}: {{s -> s.length()}}|ClassCastException|{{2}}|
> |{{d}}: {{s -> s.toString()}}|ClassCastException|{{ab}}|
> |{{e}}: closure {{{ it.toUpperCase() }}}|{{AB}} on master (CCE before 
> GROOVY-12469 follow-up)|{{AB}}|
> The lambda's parameter is compiled as {{String}}, so the cast happens in the 
> bridge that {{LambdaMetafactory}} generates for {{Function.apply(Object)}}, 
> before any generated code can convert the value. A possible fix is to give 
> the synthetic lambda method an erased parameter type when the parameter type 
> comes from generics, then convert a {{GString}} to {{String}} inside the 
> lambda, as is now done for closure parameters. The method reference case 
> would need the same treatment through a synthetic lambda.
> Related observation: in dynamic code, {{String::toUpperCase}} applied to a 
> {{GString}} throws {{MissingMethodException}}, while {{s -> s.toUpperCase()}} 
> works. That may be worth handling separately.



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

Reply via email to