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

Paul King resolved GROOVY-12747.
--------------------------------
    Fix Version/s: 7.0.0-alpha-1
         Assignee: Paul King
       Resolution: Fixed

> STC: assigning to a closure or lambda parameter typed from a functional 
> interface converts the value to the inferred type
> -------------------------------------------------------------------------------------------------------------------------
>
>                 Key: GROOVY-12747
>                 URL: https://issues.apache.org/jira/browse/GROOVY-12747
>             Project: Groovy
>          Issue Type: Bug
>            Reporter: Paul King
>            Assignee: Paul King
>            Priority: Major
>             Fix For: 7.0.0-alpha-1
>
>
> Under {{@TypeChecked}} and {{@CompileStatic}}, an untyped closure or lambda 
> parameter whose type is inferred from a functional-interface parameter 
> behaves as a declared, typed parameter. Assigning a value of another type to 
> the parameter therefore converts the value to the parameter's type, silently 
> or with a {{GroovyCastException}}. Dynamic Groovy keeps the value.
> {code:groovy}
> @groovy.transform.TypeChecked // or @CompileStatic
> def test() {
>     List<Integer> numbers = [1, 2]
>     numbers.stream().map { n -> n = n.toString(); n }.toList()
> }
> assert test() == [1, 2] // fails: [49, 50]
> {code}
> ||Closure (for {{Stream.map}} on {{List<Integer>}} [1, 
> 2])||Dynamic||{{@TypeChecked}} / {{@CompileStatic}}||
> |{{\{ n -> n = n.toString(); n \}}}|[1, 2]|*[49, 50]*, the char codes of "1" 
> and "2"|
> |{{\{ n -> n = n + 0.5; n \}}}|[1.5, 2.5]|*[1, 2]*, truncated|
> |{{n -> \{ n = 'x'; n \}}} (lambda)|[x, x]|*[120, 120]*|
> |{{Function<Integer, Object> f = \{ n -> n = 'x'; n \}}}|[x, x]|*[120, 120]*|
> |{{\{ n -> n = 'ab'; n \}}}|[ab, ab]|{{GroovyCastException}}: Cannot cast 
> object 'ab' with class 'java.lang.String' to class 'java.lang.Integer'|
> |{{\{ it = 'x'; it \}}} (implicit parameter)|[x, x]|[x, x]|
> |DGM {{numbers.collect \{ n -> n = n.toString(); n \}}} 
> ({{@ClosureParams}})|[1, 2]|[1, 2]|
> So the same closure body behaves differently depending on how its parameter 
> type was inferred. A parameter typed through {{@ClosureParams}}, or an 
> implicit {{it}}, keeps the assigned value, as dynamic Groovy does. A 
> parameter typed from a functional interface converts it.
> h3. Cause
> {{StaticTypeCheckingVisitor.inferParameterAndReturnTypesOfClosureOnRHS}} sets 
> the inferred type on an untyped parameter ({{parameter.setType(type)}}, 
> commented "GROOVY-11083, GROOVY-11085, et al."). The parameter is then 
> declared with that type, so an assignment to it goes through a cast to the 
> parameter type: a one-character String becomes its char code, a 
> {{BigDecimal}} is narrowed to {{Integer}}, and other Strings fail. The 
> {{@ClosureParams}} path ({{processClosureParams}}) records the inferred types 
> without changing the parameters' declared type, so flow typing applies.
> h3. Expected
> The assignment must not silently change the value. Either:
> * treat the parameter as the {{@ClosureParams}} path does, so it keeps the 
> assigned value as in dynamic Groovy; or
> * report a static type error for an assignment that is incompatible with the 
> inferred type, as Java does for a lambda parameter.
> The first is consistent with the rest of Groovy's closure handling. Whichever 
> is chosen, the {{@ClosureParams}} and functional-interface paths should agree.
> h3. Notes
> * Seen on master. {{setType}} dates from GROOVY-11083 and GROOVY-11085 
> (3.0.18 / 4.0.13); earlier versions were not checked.
> * GROOVY-12746 types the parameters of closures passed to extension methods 
> with functional-interface parameters, such as {{collectParallel}}, from the 
> receiver. Those closures now have this behaviour too: 
> {{numbers.collectParallel \{ n -> n = n.toString(); n \}}} gives [49, 50]. 
> Before GROOVY-12746 their parameters fell back to {{Object}}.



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

Reply via email to