Scott Murphy Heiberg created GROOVY-12757:
---------------------------------------------

             Summary: STC: a lambda result naming a type parameter of the 
calling method takes the receiver's type argument for that name
                 Key: GROOVY-12757
                 URL: https://issues.apache.org/jira/browse/GROOVY-12757
             Project: Groovy
          Issue Type: Bug
          Components: Static Type Checker
    Affects Versions: 6.0.0
            Reporter: Scott Murphy Heiberg


When a generic method of a generic receiver is called with a lambda whose 
result names a type parameter of the calling method, and the receiver's class 
has a type parameter of the same name, static type checking replaces the 
caller's type parameter with the receiver's type argument:

{code:groovy}
import java.util.concurrent.CompletableFuture
import java.util.function.Function

@groovy.transform.CompileStatic
class C {
    static <T> Optional<List<T>> wrap(Optional<String> value, T item) {
        Optional<List<T>> result = value.map((String s) -> [item] as List<T>)
        result
    }
    static <T> CompletableFuture<List<T>> each(CompletableFuture<List<Object>> 
future, Function<Object, T> fn) {
        CompletableFuture<List<T>> result = future.thenApply((List<Object> 
values) -> values.collect { fn.apply(it) } as List<T>)
        result
    }
}
{code}
{noformat}
[Static type checking] - Incompatible generic argument types. Cannot assign 
java.util.Optional<java.util.List<java.lang.String>> to: 
java.util.Optional<java.util.List<T>>
[Static type checking] - Incompatible generic argument types. Cannot assign 
java.util.concurrent.CompletableFuture<java.util.List<java.util.List<java.lang.Object>>>
 to: java.util.concurrent.CompletableFuture<java.util.List<T>>
{noformat}

{{map}}'s {{U}} is inferred from the lambda as {{List<T>}}, with the calling 
method's {{T}}, and then {{Optional}}'s own {{T}}, here {{String}}, is applied 
to the result. Groovy before GROOVY-12714 inferred the same wrong type, but its 
assignment check accepted it. Renaming the calling method's type parameter 
avoids the problem, and javac accepts the equivalent Java.

{{StaticTypeCheckingVisitor#inferReturnTypeGenerics}} resolves the method's 
type parameters from the arguments first, and then applies the receiver's type 
arguments to the result. Applying the receiver's type arguments to the declared 
return type first keeps them away from the types the arguments supply. 
{{extractPlaceHoldersVisibleToDeclaration}} already leaves out the method's own 
type parameters (GROOVY-10322), so a method type parameter that shadows the 
class's is unaffected.

Grails' {{AwaitablePromiseFactory}}, which calls 
{{groovy.concurrent.Awaitable#then}} that way, no longer compiles against 
GROOVY_6_0_X because of this.



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

Reply via email to