This is an automated email from the ASF dual-hosted git repository.

emilles pushed a commit to branch GROOVY-11685
in repository https://gitbox.apache.org/repos/asf/groovy.git

commit 67af81026f39e8c27c98b87901bb54e5b2a4fec8
Author: Eric Milles <[email protected]>
AuthorDate: Sat May 31 11:37:17 2025 -0500

    GROOVY-11685: STC: `null` or `void` return within closure expression
---
 .../groovy/transform/stc/StaticTypeCheckingVisitor.java |  5 +++--
 .../groovy/groovy/transform/stc/ClosuresSTCTest.groovy  | 17 +++++++++++++++++
 2 files changed, 20 insertions(+), 2 deletions(-)

diff --git 
a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
 
b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
index fa7df3da1e..2605a17e2e 100644
--- 
a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ 
b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -2397,7 +2397,7 @@ out:    if ((samParameterTypes.length == 1 && 
isOrImplements(samParameterTypes[0
 
     protected ClassNode checkReturnType(final ReturnStatement statement) {
         Expression expression = statement.getExpression();
-        ClassNode type = getType(expression);
+        var type = statement.isReturningNullOrVoid() ? VOID_TYPE : 
getType(expression); // GROOVY-11685
 
         TypeCheckingContext.EnclosingClosure enclosingClosure = 
typeCheckingContext.getEnclosingClosure();
         if (enclosingClosure != null) {
@@ -2419,7 +2419,8 @@ out:    if ((samParameterTypes.length == 1 && 
isOrImplements(samParameterTypes[0
                 } else if (statement.isReturningNullOrVoid() ? 
!isPrimitiveType(inferredReturnType) // GROOVY-7713, GROOVY-8202
                      : 
GenericsUtils.buildWildcardType(wrapTypeIfNecessary(inferredReturnType)).isCompatibleWith(wrapTypeIfNecessary(type)))
 {
                     type = inferredReturnType; // GROOVY-8310, GROOVY-10082, 
GROOVY-10091, GROOVY-10128, GROOVY-10306: allow simple covariance
-                } else if (!isPrimitiveVoid(type) && 
!extension.handleIncompatibleReturnType(statement, type)) { // GROOVY-10277: 
incompatible
+                } else if ((statement.isReturningNullOrVoid() || 
!isPrimitiveVoid(type)) && !extension.handleIncompatibleReturnType(statement, 
type)) {
+                    // GROOVY-10277, GROOVY-11490: incompatible return 
statement (null for primitive or inconvertible type)
                     String value = (statement.isReturningNullOrVoid() ? "null" 
: "value of type " + prettyPrintType(type));
                     String which = (enclosingClosure.getClosureExpression() 
instanceof LambdaExpression ? "lambda" : "closure");
                     addStaticTypeError("Cannot return " + value + " for " + 
which + " expecting " + prettyPrintType(inferredReturnType), expression);
diff --git a/src/test/groovy/groovy/transform/stc/ClosuresSTCTest.groovy 
b/src/test/groovy/groovy/transform/stc/ClosuresSTCTest.groovy
index 3bec5b2998..856cc3c4bd 100644
--- a/src/test/groovy/groovy/transform/stc/ClosuresSTCTest.groovy
+++ b/src/test/groovy/groovy/transform/stc/ClosuresSTCTest.groovy
@@ -429,6 +429,23 @@ class ClosuresSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
+    // GROOVY-11685
+    void testCollect3() {
+        assertScript '''
+            List<Number> test(List<String> strings) {
+                List<Number> numbers = []
+                if (true) {
+                    numbers = strings.collect { string ->
+                        if (!string.isNumber()) return
+                        (Number) Integer.parseInt(string)
+                    }
+                }
+                numbers
+            }
+            assert test(['1','2','3','x']) == [1,2,3,null]
+        '''
+    }
+
     void testWithIntReturnType() {
         assertScript '''
             class Test {

Reply via email to