[
https://issues.apache.org/jira/browse/GROOVY-12746?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Paul King resolved GROOVY-12746.
--------------------------------
Fix Version/s: 7.0.0-alpha-1
Assignee: Paul King
Resolution: Fixed
> STC: type closure and lambda parameters for an extension method's functional
> parameter from the receiver
> --------------------------------------------------------------------------------------------------------
>
> Key: GROOVY-12746
> URL: https://issues.apache.org/jira/browse/GROOVY-12746
> Project: Groovy
> Issue Type: Bug
> Reporter: Paul King
> Assignee: Paul King
> Priority: Major
> Fix For: 7.0.0-alpha-1
>
>
> When an extension method declares a functional-interface parameter in terms
> of a type parameter that appears only in its {{self}} parameter, static type
> checking does not infer that type parameter from the receiver. The closure or
> lambda parameters fall back to the type parameter's bound, usually {{Object}}.
> {code:groovy}
> @groovy.transform.CompileStatic
> void test() {
> List<Integer> numbers = [1, 2, 3]
> numbers.collectParallel { it * 2 } // Cannot find matching method
> java.lang.Object#multiply(int)
> numbers.findAllParallel { it > 1 } // Cannot find matching method
> java.lang.Object#compareTo(int)
> numbers.sumParallel { a, b -> a + b } // Cannot find matching method
> java.lang.Object#plus(java.lang.Object)
> }
> {code}
> Every method of {{ParallelCollectionExtensions}} is affected, including the
> documented {{amounts.sumParallel \{ a, b -> a + b \}}}. So is any extension
> method, in an extension module or a DGM-like class, whose functional
> parameter has no {{Closure}} overload with {{@ClosureParams}} to fall back
> on. Most DGM methods have such an overload, which is why the problem rarely
> shows.
> The same call written as a static call infers correctly, because the receiver
> is then an ordinary argument:
> {code:groovy}
> ParallelCollectionExtensions.collectParallel(numbers) { it * 2 } // OK
> {code}
> h3. Cause
> {{StaticTypeCheckingVisitor.inferClosureParameterTypes}} infers a method's
> type parameters from explicit type arguments, then from the call's arguments,
> then falls back to their bounds. For an extension method the receiver is the
> {{self}} argument, but it is not among the call's arguments, so a type
> parameter that only {{self}} mentions is never connected to the receiver.
> h3. Fix
> For a non-static extension method, connect the receiver's type to the
> {{self}} parameter's type after the arguments, so the receiver fills only
> type parameters that the arguments leave unresolved. Inference that worked
> before is unchanged. Closures and lambdas that used to be typed with the
> bound are now typed from the receiver. That matters in two ways:
> * *Errors:* a body that is invalid for the actual element type is now
> reported with that type, for example {{Integer#toUpperCase()}} for
> {{List<Integer>}} and {{\{ it.toUpperCase() \}}}, not
> {{Object#toUpperCase()}}.
> * *Overloads:* a call in the body that passes the parameter to an overloaded
> method can now select a more specific overload under static compilation, such
> as {{helper(Integer)}} instead of {{helper(Object)}}. Dynamic Groovy already
> selects that overload.
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)