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

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

commit 7ba3a2ce74dc36a8f145607c942f7342b2f8a5ab
Author: Eric Milles <[email protected]>
AuthorDate: Wed Apr 16 15:15:43 2025 -0500

    GROOVY-11623: STC: support return of list expression for array method
---
 .../transform/stc/StaticTypeCheckingSupport.java   | 29 ++++---
 .../transform/stc/StaticTypeCheckingVisitor.java   |  2 +
 .../groovy/transform/stc/ReturnsSTCTest.groovy     | 92 ++++++++++++++++++----
 .../transform/stc/TypeInferenceSTCTest.groovy      | 36 +++++++++
 4 files changed, 131 insertions(+), 28 deletions(-)

diff --git 
a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
 
b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
index 4867825693..e075f7eb0a 100644
--- 
a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
+++ 
b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
@@ -652,23 +652,26 @@ public abstract class StaticTypeCheckingSupport {
         }
 
         if (left.isArray()) {
+            ClassNode leftItemType = left.getComponentType();
             if (right.isArray()) {
-                ClassNode leftComponent = left.getComponentType();
-                ClassNode rightComponent = right.getComponentType();
-                return (isPrimitiveType(leftComponent) && 
!isPrimitiveBoolean(leftComponent))
-                        ? isPrimitiveType(rightComponent) // GROOVY-11371: 
primitive array only
-                        : checkCompatibleAssignmentTypes(leftComponent, 
rightComponent, rightExpression, false);
-            }
-            if (GeneralUtils.isOrImplements(right, Collection_TYPE) && 
!(rightExpression instanceof ListExpression)) {
-                GenericsType elementType = 
GenericsUtils.parameterizeType(right, Collection_TYPE).getGenericsTypes()[0];
-                return OBJECT_TYPE.equals(left.getComponentType()) // Object[] 
can accept any collection element type(s)
-                    || (elementType.getLowerBound() == null && 
isCovariant(extractType(elementType), left.getComponentType()));
+                ClassNode rightItemType = right.getComponentType();
+                return (isPrimitiveType(leftItemType) && 
!isPrimitiveBoolean(leftItemType))
+                        ? isPrimitiveType(rightItemType) // GROOVY-11371: 
primitive array only
+                        : checkCompatibleAssignmentTypes(leftItemType, 
rightItemType, rightExpression, false);
+            }
+            if (rightExpression instanceof ListExpression) {
+                return true; // addPrecisionErrors checks values
+            }
+            if (GeneralUtils.isOrImplements(right, Collection_TYPE)) {
+                var elementType = GenericsUtils.parameterizeType(right, 
Collection_TYPE).getGenericsTypes()[0];
+                return isObjectType(leftItemType) // Object[] can accept any 
collection element type(s)
+                    || (elementType.getLowerBound() == null && 
isCovariant(extractType(elementType), leftItemType));
                     //  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ GROOVY-8984: "? 
super T" is only compatible with an Object[] target
             }
             if (GeneralUtils.isOrImplements(right, BaseStream_TYPE)) {
-                GenericsType elementType = 
GenericsUtils.parameterizeType(right, BaseStream_TYPE).getGenericsTypes()[0];
-                return isObjectType(left.getComponentType()) // Object[] can 
accept any stream API element type(s)
-                    || (elementType.getLowerBound() == null && 
isCovariant(extractType(elementType), getWrapper(left.getComponentType())));
+                var elementType = GenericsUtils.parameterizeType(right, 
BaseStream_TYPE).getGenericsTypes()[0];
+                return isObjectType(leftItemType) // Object[] can accept any 
stream API element type(s)
+                    || (elementType.getLowerBound() == null && 
isCovariant(extractType(elementType), getWrapper(leftItemType)));
             }
         }
 
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 94dd15e53d..d4a9615888 100644
--- 
a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ 
b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -2427,6 +2427,8 @@ out:    if ((samParameterTypes.length == 1 && 
isOrImplements(samParameterTypes[0
                 BinaryExpression dummy = assignX(varX("{target}", returnType), 
expression, statement);
                 ClassNode resultType = getResultType(returnType, ASSIGN, type, 
dummy); // GROOVY-10295
                 checkTypeGenerics(returnType, resultType, expression);
+            } else { // GROOVY-11623: check array items or number bounds
+                addPrecisionErrors(returnType.redirect(), returnType, type, 
expression);
             }
         }
         return null;
diff --git a/src/test/groovy/groovy/transform/stc/ReturnsSTCTest.groovy 
b/src/test/groovy/groovy/transform/stc/ReturnsSTCTest.groovy
index 1172243665..67a789bd0b 100644
--- a/src/test/groovy/groovy/transform/stc/ReturnsSTCTest.groovy
+++ b/src/test/groovy/groovy/transform/stc/ReturnsSTCTest.groovy
@@ -29,7 +29,8 @@ class ReturnsSTCTest extends StaticTypeCheckingTestCase {
             }
 
             int x = method()
-        ''', 'Cannot assign value of type void to variable of type int'
+        ''',
+        'Cannot assign value of type void to variable of type int'
     }
 
     void testIncompatibleExplicitReturn() {
@@ -39,7 +40,8 @@ class ReturnsSTCTest extends StaticTypeCheckingTestCase {
             }
 
             int x = method()
-        ''', 'Cannot assign value of type java.lang.String to variable of type 
int'
+        ''',
+        'Cannot assign value of type java.lang.String to variable of type int'
     }
 
     void testIncompatibleExplicitReturn2() {
@@ -47,7 +49,8 @@ class ReturnsSTCTest extends StaticTypeCheckingTestCase {
             int method() {
                 return 'String'
             }
-        ''', 'Cannot return value of type java.lang.String for method 
returning int'
+        ''',
+        'Cannot return value of type java.lang.String for method returning int'
     }
 
     void testIncompatibleImplicitReturn2() {
@@ -55,7 +58,8 @@ class ReturnsSTCTest extends StaticTypeCheckingTestCase {
             int method() {
                 'String'
             }
-        ''', 'Cannot return value of type java.lang.String for method 
returning int'
+        ''',
+        'Cannot return value of type java.lang.String for method returning int'
     }
 
     void testIncompatibleImplicitReturn() {
@@ -65,7 +69,8 @@ class ReturnsSTCTest extends StaticTypeCheckingTestCase {
             }
 
             int x = method()
-        ''', 'Cannot assign value of type java.lang.String to variable of type 
int'
+        ''',
+        'Cannot assign value of type java.lang.String to variable of type int'
     }
 
     void testImplicitReturnFailureWithIfElse() {
@@ -77,7 +82,8 @@ class ReturnsSTCTest extends StaticTypeCheckingTestCase {
                     2
                 }
             }
-        ''', 'Cannot return value of type java.lang.String for method 
returning int'
+        ''',
+        'Cannot return value of type java.lang.String for method returning int'
     }
 
     void testImplicitReturnFailureWithIfElse2() {
@@ -89,7 +95,8 @@ class ReturnsSTCTest extends StaticTypeCheckingTestCase {
                     'String'
                 }
             }
-        ''', 'Cannot return value of type java.lang.String for method 
returning int'
+        ''',
+        'Cannot return value of type java.lang.String for method returning int'
     }
 
     void testImplicitReturnFailureWithIfElse3() {
@@ -145,7 +152,8 @@ class ReturnsSTCTest extends StaticTypeCheckingTestCase {
             double greeting(String name) {
                 new Object()
             }
-        ''', 'Cannot return value of type java.lang.Object for method 
returning double'
+        ''',
+        'Cannot return value of type java.lang.Object for method returning 
double'
     }
 
     void testRecursiveTypeInferrence() {
@@ -169,14 +177,13 @@ class ReturnsSTCTest extends StaticTypeCheckingTestCase {
 
     void testReturnTypeInferrenceInSingleClass() {
         assertScript '''
-        class Foo {
-            int square(int i) { i*i }
-
-            int foo(int i) {
-                square(i)
+            class Foo {
+                int square(int i) { i*i }
+                int foo(int i) {
+                    square(i)
+                }
             }
-        }
-        new Foo().foo(2)
+            new Foo().foo(2)
         '''
     }
 
@@ -251,6 +258,61 @@ class ReturnsSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
+    // GROOVY-11623
+    void testImplicitReturnToArray() {
+        assertScript '''
+            int[] foo() {
+                []
+            }
+            int[] bar() {
+                [0]
+            }
+            assert foo().length == 0
+            assert bar().length == 1
+        '''
+
+        shouldFailWithMessages '''
+            int[] baz() {
+                [null]
+            }
+        ''',
+        'Cannot assign value of type java.lang.Object into array of type int[]'
+
+        assertScript '''
+            Number[] foo() {
+                []
+            }
+            Number[] bar() {
+                [0]
+            }
+            Number[] baz() {
+                [null]
+            }
+            assert foo().length == 0
+            assert bar().length == 1
+            assert baz().length == 1
+        '''
+
+        shouldFailWithMessages '''
+            Integer[] baz() {
+                [new Object()]
+            }
+        ''',
+        'Cannot assign value of type java.lang.Object into array of type 
java.lang.Integer[]'
+
+        assertScript '''
+            Object[][] foo() {
+                []
+            }
+            Object[][] bar() {
+                [[]]
+            }
+            assert foo().length == 0
+            assert bar().length == 1
+            assert bar()[0].length == 0
+        '''
+    }
+
     // GROOVY-5835
     void testReturnInClosureShouldNotBeConsideredAsReturnOfEnclosingMethod() {
         assertScript '''
diff --git a/src/test/groovy/groovy/transform/stc/TypeInferenceSTCTest.groovy 
b/src/test/groovy/groovy/transform/stc/TypeInferenceSTCTest.groovy
index 508be6d96f..bb12727f5c 100644
--- a/src/test/groovy/groovy/transform/stc/TypeInferenceSTCTest.groovy
+++ b/src/test/groovy/groovy/transform/stc/TypeInferenceSTCTest.groovy
@@ -1500,6 +1500,42 @@ class TypeInferenceSTCTest extends 
StaticTypeCheckingTestCase {
         '''
     }
 
+    // GROOVY-11623
+    void testAnnotationDefaults() {
+        assertScript '''
+            import java.lang.annotation.*
+
+            @Retention(RetentionPolicy.RUNTIME)
+            @Target(ElementType.TYPE)
+            @interface A {
+                int     iType() default 1
+                long    lType() default 1
+                short   sType() default 1
+                float   fType() default 1f
+                double  dType() default 1d
+                boolean bType() default true
+                char    cType() default 'c'
+                String  chars() default 's'
+                Class   tType() default Object
+                Class[] xType() default [] // TODO: {} -- GROOVY-11492
+            }
+
+            @A class C {
+            }
+
+            assert C.getAnnotation(A).iType() == 1
+            assert C.getAnnotation(A).lType() == 1L
+            assert C.getAnnotation(A).sType() == (short) 1
+            assert C.getAnnotation(A).fType() == 1.0f
+            assert C.getAnnotation(A).dType() == 1.0d
+            assert C.getAnnotation(A).bType() == true
+            assert C.getAnnotation(A).cType() == (char) 'c'
+            assert C.getAnnotation(A).chars() == "s"
+            assert C.getAnnotation(A).tType() == Object.class
+            assert C.getAnnotation(A).xType() == new Class[0]
+        '''
+    }
+
     // GROOVY-
     void testGetAnnotationFails() {
         assertScript '''

Reply via email to