codeconsole opened a new pull request, #3126:
URL: https://github.com/apache/groovy/pull/3126

   Static type checking accepted a value whose static type is `Closure<R>` when 
it was passed as a method argument or returned from a method, and the target 
was a parameterized functional interface whose method does not return `R`:
   
   ```groovy
   @CompileStatic
   class C {
       static String take(Supplier<String> s) { s.get().toLowerCase() }
       static Supplier<String> make() { Closure<Integer> c = { 1 }; c }
       static void main(args) {
           Closure<Integer> c = { 1 }
           take(c)                     // ClassCastException: Integer cannot be 
cast to String
           make().get().toLowerCase()  // ClassCastException
       }
   }
   ```
   
   4.0.33, 5.0.8 and 6.0.0 behave the same. A closure literal in the same place 
is rejected ("Cannot return value of type int for closure expecting 
java.lang.String").
   
   For an argument, 
`StaticTypeCheckingSupport.typeCheckMethodArgumentWithGenerics` accepted any 
`Closure` for a SAM-type parameter and assumed the return type had been checked 
earlier. That holds only for closure literals. For a return, 
`StaticTypeCheckingVisitor.checkReturnType` checked generics only when the 
value's type implements the return type, which `Closure` does not for most SAM 
types.
   
   The new `StaticTypeCheckingSupport.isClosureCoercibleToSAM` accepts the 
value when:
   - the SAM method returns void;
   - it returns a type that accepts `R`;
   - it returns `String` and `R` is `GString`, matching what a closure literal 
is allowed to do.
   
   Both paths now use it. This includes a non-generic subclass of `Closure<R>` 
passed as an argument (`class D extends Closure<Integer>`; `take(new D())`), 
whose `R` is found through the superclass. A raw `Closure`, `Closure<Object>` 
or unresolved `R` is accepted as before. Closure and lambda literals keep their 
own return check. Method pointers and references are not checked here, because 
the type of a pointer to an overloaded method such as `Math.&abs` names only 
one of the overloads.
   
   Mismatches are now reported as `Cannot call 
C#take(java.util.function.Supplier<java.lang.String>) with arguments 
[groovy.lang.Closure<java.lang.Integer>]` and `Cannot return value of type 
groovy.lang.Closure<java.lang.Integer> for method returning 
java.util.function.Supplier<java.lang.String>`.
   
   A local variable initialised from a closure literal is flow-typed from it, 
so `def c = { 1 }; take(c)` for `take(Supplier<String>)` is now rejected as 
`Closure<Integer>`, as `Supplier<String> s = c` already is. `take((Closure) c)` 
or `c as Supplier<String>` still compile.
   
   This PR and #3113 (GROOVY-12588, assignment) each add an 
`isClosureCoercibleToSAM` helper; whichever lands second should fold its helper 
into the other.
   
   ## Tests
   
   `CoercionSTCTest.testCoerceClosureArgumentToFunctionalInterface2` and 
`testCoerceClosureReturnToFunctionalInterface2` fail without the change, under 
both `@TypeChecked` and `@CompileStatic` (`CoercionStaticCompileTests`). 
`testCoerceClosureArgumentToFunctionalInterface` and 
`testCoerceClosureReturnToFunctionalInterface` cover the cases that stay 
accepted. `groovy.transform.stc.*`, `org.codehaus.groovy.classgen.asm.sc.*`, 
`groovy.bugs.*`, `gls.*`, `org.codehaus.groovy.transform.traitx.*`, 
`groovy.lang.*` and `groovy.ClosureTest` pass. The Checkstyle and CodeNarc 
gates pass.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to