You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by em...@apache.org on 2022/05/19 16:11:46 UTC

[groovy] branch GROOVY_4_0_X updated (7e53af5ae9 -> a3fb16ecdb)

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

emilles pushed a change to branch GROOVY_4_0_X
in repository https://gitbox.apache.org/repos/asf/groovy.git


    from 7e53af5ae9 GROOVY-10624: add test case
     new f10d24690a GROOVY-10266: add test case
     new 83bca9c6d8 GROOVY-10092: STC: cannot assign `boolean` to non-`boolean` primitives
     new a3fb16ecdb GROOVY-10342: STC: type parameter can accept parameterized return values

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../transform/stc/StaticTypeCheckingSupport.java   | 79 ++++++++++++----------
 .../transform/stc/StaticTypeCheckingVisitor.java   | 11 ++-
 src/test/groovy/transform/stc/BugsSTCTest.groovy   | 13 ++--
 .../groovy/transform/stc/GenericsSTCTest.groovy    | 51 +++++++++++++-
 4 files changed, 105 insertions(+), 49 deletions(-)


[groovy] 03/03: GROOVY-10342: STC: type parameter can accept parameterized return values

Posted by em...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit a3fb16ecdb127760697e5f7317f113c56fea9be0
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Thu May 19 10:41:43 2022 -0500

    GROOVY-10342: STC: type parameter can accept parameterized return values
---
 .../transform/stc/StaticTypeCheckingSupport.java   | 33 +++++++++++++---------
 .../transform/stc/StaticTypeCheckingVisitor.java   | 11 ++++++--
 .../groovy/transform/stc/GenericsSTCTest.groovy    | 31 +++++++++++++++++++-
 3 files changed, 57 insertions(+), 18 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 b4a76624a8..336de67bac 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
@@ -121,6 +121,7 @@ import static org.codehaus.groovy.ast.ClassHelper.make;
 import static org.codehaus.groovy.ast.ClassHelper.makeWithoutCaching;
 import static org.codehaus.groovy.ast.ClassHelper.short_TYPE;
 import static org.codehaus.groovy.ast.ClassHelper.void_WRAPPER_TYPE;
+import static org.codehaus.groovy.ast.tools.WideningCategories.implementsInterfaceOrSubclassOf;
 import static org.codehaus.groovy.ast.tools.WideningCategories.isFloatingCategory;
 import static org.codehaus.groovy.ast.tools.WideningCategories.isLongCategory;
 import static org.codehaus.groovy.ast.tools.WideningCategories.lowestUpperBound;
@@ -698,11 +699,21 @@ public abstract class StaticTypeCheckingSupport {
             if (isNumberType(rightRedirect) /*|| rightRedirect == char_TYPE*/) {
                 return true;
             }
+            if (leftRedirect == char_TYPE && rightRedirect == Character_TYPE) return true;
+            if (leftRedirect == Character_TYPE && rightRedirect == char_TYPE) return true;
+            if ((leftRedirect == char_TYPE || leftRedirect == Character_TYPE) && rightRedirect == STRING_TYPE) {
+                return rightExpression instanceof ConstantExpression && rightExpression.getText().length() == 1;
+            }
         } else if (isFloatingCategory(getUnwrapper(leftRedirect))) {
             // float or double can be assigned any base number type or BigDecimal
             if (isNumberType(rightRedirect) || isBigDecimalType(rightRedirect)) {
                 return true;
             }
+        } else if (left.isGenericsPlaceHolder()) { // must precede non-final types
+            return right.getUnresolvedName().charAt(0) != '#' // RHS not adaptable
+                    ? left.getGenericsTypes()[0].isCompatibleWith(right) // GROOVY-7307, GROOVY-9952, et al.
+                    : implementsInterfaceOrSubclassOf(leftRedirect, rightRedirect); // GROOVY-10067, GROOVY-10342
+
         } else if (isBigDecimalType(leftRedirect) || Number_TYPE.equals(leftRedirect)) {
             // BigDecimal or Number can be assigned any derivitave of java.lang.Number
             if (isNumberType(rightRedirect) || rightRedirect.isDerivedFrom(Number_TYPE)) {
@@ -713,22 +724,16 @@ public abstract class StaticTypeCheckingSupport {
             if (isLongCategory(getUnwrapper(rightRedirect)) || rightRedirect.isDerivedFrom(BigInteger_TYPE)) {
                 return true;
             }
+        } else if (leftRedirect.isDerivedFrom(Enum_Type)) {
+            // Enum types can be assigned String or GString (triggers `valueOf` call)
+            if (rightRedirect == STRING_TYPE || isGStringOrGStringStringLUB(rightRedirect)) {
+                return true;
+            }
         } else if (isWildcardLeftHandSide(leftRedirect)) {
             // Object, String, [Bb]oolean or Class can be assigned anything (except null to boolean)
             return !(leftRedirect == boolean_TYPE && isNullConstant(rightExpression));
         }
 
-        if (leftRedirect == char_TYPE && rightRedirect == Character_TYPE) return true;
-        if (leftRedirect == Character_TYPE && rightRedirect == char_TYPE) return true;
-        if ((leftRedirect == char_TYPE || leftRedirect == Character_TYPE) && rightRedirect == STRING_TYPE) {
-            return rightExpression instanceof ConstantExpression && rightExpression.getText().length() == 1;
-        }
-
-        // if left is an enum and right is String or GString we do valueOf
-        if (leftRedirect.isDerivedFrom(Enum_Type) && (rightRedirect == STRING_TYPE || isGStringType(rightRedirect))) {
-            return true;
-        }
-
         // if right is array, map or collection we try invoking the constructor
         if (allowConstructorCoercion && isGroovyConstructorCompatible(rightExpression)) {
             // TODO: in case of the array we could maybe make a partial check
@@ -745,9 +750,6 @@ public abstract class StaticTypeCheckingSupport {
             return true;
         }
 
-        if (left.isGenericsPlaceHolder()) {
-            return left.getGenericsTypes()[0].isCompatibleWith(right);
-        }
         // GROOVY-7316, GROOVY-10256: "Type x = m()" given "def <T> T m()"; T adapts to target
         return right.isGenericsPlaceHolder() && right.asGenericsType().isCompatibleWith(left);
     }
@@ -865,6 +867,9 @@ public abstract class StaticTypeCheckingSupport {
      * with trailing "[]".
      */
     static String prettyPrintType(final ClassNode type) {
+        if (type.getUnresolvedName().charAt(0) == '#') {
+            return type.redirect().toString(false);
+        }
         return type.toString(false);
     }
 
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 1959534633..e06abf7932 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -848,7 +848,10 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
                 if (rightExpression instanceof ConstructorCallExpression)
                     inferDiamondType((ConstructorCallExpression) rightExpression, lType);
 
-                if (lType.isUsingGenerics() && missesGenericsTypes(resultType)) {
+                if (lType.isUsingGenerics()
+                        && missesGenericsTypes(resultType)
+                        // GROOVY-10324, GROOVY-10342, et al.
+                        && !resultType.isGenericsPlaceHolder()) {
                     // unchecked assignment
                     // List<Type> list = new LinkedList()
                     // Iterable<Type> iter = new LinkedList()
@@ -858,8 +861,10 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
                     // the inferred type of the binary expression is the type of the RHS
                     // "completed" with generics type information available from the LHS
                     if (lType.equals(resultType)) {
+                        // GROOVY-6126, GROOVY-6558, GROOVY-6564, et al.
                         if (!lType.isGenericsPlaceHolder()) resultType = lType;
-                    } else if (!resultType.isGenericsPlaceHolder()) { // GROOVY-10324
+                    } else {
+                        // GROOVY-5640, GROOVY-9033, GROOVY-10220, GROOVY-10235, et al.
                         Map<GenericsTypeName, GenericsType> gt = new HashMap<>();
                         extractGenericsConnections(gt, resultType, resultType.redirect());
                         ClassNode sc = resultType;
@@ -867,7 +872,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
                         } while (sc != null && !sc.equals(lType));
                         extractGenericsConnections(gt, lType, sc);
 
-                        resultType = applyGenericsContext(gt, resultType.redirect());// GROOVY-10235, et al.
+                        resultType = applyGenericsContext(gt, resultType.redirect());
                     }
                 }
 
diff --git a/src/test/groovy/transform/stc/GenericsSTCTest.groovy b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
index ef29fbb97c..6dd1a9333d 100644
--- a/src/test/groovy/transform/stc/GenericsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
@@ -472,7 +472,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
                 chars()
             }
         ''',
-        'Cannot return value of type #T for method returning java.util.List'
+        'Cannot return value of type java.lang.CharSequence for method returning java.util.List'
     }
 
     // GROOVY-10098
@@ -1443,6 +1443,35 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
+    // GROOVY-10342
+    void testAssignmentShouldWorkForParameterizedType2() {
+        assertScript '''
+            class C<T> {
+                T t
+            }
+            def <X> X m() {
+                123
+            }
+            def <N extends Number> void test() {
+                int x = m()
+                Integer y = m()
+                C<Integer> z = new C<>(); z.t = m()
+
+                C<N> c_of_n = new C<N>(); c_of_n.t = m() // Cannot assign value of type #X to variable of type N
+            }
+            test()
+        '''
+
+        shouldFailWithMessages '''
+            def <X extends CharSequence> X m() {
+            }
+            def <N extends Number> void test() {
+                N n = m()
+            }
+        ''',
+        'Cannot assign value of type java.lang.CharSequence to variable of type N'
+    }
+
     // GROOVY-9555
     void testAssignmentShouldWorkForProperUpperBound() {
         assertScript '''


[groovy] 02/03: GROOVY-10092: STC: cannot assign `boolean` to non-`boolean` primitives

Posted by em...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 83bca9c6d88f720a6a5b61074ed8cd9c77d2368b
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Wed May 18 16:51:06 2022 -0500

    GROOVY-10092: STC: cannot assign `boolean` to non-`boolean` primitives
---
 .../transform/stc/StaticTypeCheckingSupport.java   | 48 +++++++++++-----------
 src/test/groovy/transform/stc/BugsSTCTest.groovy   | 13 ++----
 2 files changed, 29 insertions(+), 32 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 a842fba3ea..b4a76624a8 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
@@ -121,9 +121,8 @@ import static org.codehaus.groovy.ast.ClassHelper.make;
 import static org.codehaus.groovy.ast.ClassHelper.makeWithoutCaching;
 import static org.codehaus.groovy.ast.ClassHelper.short_TYPE;
 import static org.codehaus.groovy.ast.ClassHelper.void_WRAPPER_TYPE;
-import static org.codehaus.groovy.ast.tools.WideningCategories.isBigIntCategory;
 import static org.codehaus.groovy.ast.tools.WideningCategories.isFloatingCategory;
-import static org.codehaus.groovy.ast.tools.WideningCategories.isNumberCategory;
+import static org.codehaus.groovy.ast.tools.WideningCategories.isLongCategory;
 import static org.codehaus.groovy.ast.tools.WideningCategories.lowestUpperBound;
 import static org.codehaus.groovy.runtime.DefaultGroovyMethods.asBoolean;
 import static org.codehaus.groovy.runtime.DefaultGroovyMethodsSupport.closeQuietly;
@@ -691,22 +690,34 @@ public abstract class StaticTypeCheckingSupport {
         ClassNode rightRedirect = right.redirect();
         if (leftRedirect == rightRedirect) return true;
 
-        if (rightRedirect == void_WRAPPER_TYPE) return leftRedirect == VOID_TYPE;
-        if (rightRedirect == VOID_TYPE) return leftRedirect == void_WRAPPER_TYPE;
+        if (leftRedirect == VOID_TYPE) return rightRedirect == void_WRAPPER_TYPE;
+        if (leftRedirect == void_WRAPPER_TYPE) return rightRedirect == VOID_TYPE;
 
-        if (isNumberType(rightRedirect) || isNumberCategory(rightRedirect)) {
-            if (isBigDecimalType(leftRedirect) || Number_TYPE.equals(leftRedirect)) {
-                // any number can be assigned to BigDecimal or Number
+        if (isLongCategory(getUnwrapper(leftRedirect))) {
+            // byte, char, int, long or short can be assigned any base number
+            if (isNumberType(rightRedirect) /*|| rightRedirect == char_TYPE*/) {
                 return true;
             }
-            if (isBigIntegerType(leftRedirect)) {
-                return isBigIntCategory(getUnwrapper(rightRedirect)) || rightRedirect.isDerivedFrom(BigInteger_TYPE);
+        } else if (isFloatingCategory(getUnwrapper(leftRedirect))) {
+            // float or double can be assigned any base number type or BigDecimal
+            if (isNumberType(rightRedirect) || isBigDecimalType(rightRedirect)) {
+                return true;
+            }
+        } else if (isBigDecimalType(leftRedirect) || Number_TYPE.equals(leftRedirect)) {
+            // BigDecimal or Number can be assigned any derivitave of java.lang.Number
+            if (isNumberType(rightRedirect) || rightRedirect.isDerivedFrom(Number_TYPE)) {
+                return true;
+            }
+        } else if (isBigIntegerType(leftRedirect)) {
+            // BigInteger can be assigned byte, char, int, long, short or BigInteger
+            if (isLongCategory(getUnwrapper(rightRedirect)) || rightRedirect.isDerivedFrom(BigInteger_TYPE)) {
+                return true;
             }
+        } else if (isWildcardLeftHandSide(leftRedirect)) {
+            // Object, String, [Bb]oolean or Class can be assigned anything (except null to boolean)
+            return !(leftRedirect == boolean_TYPE && isNullConstant(rightExpression));
         }
 
-        // anything can be assigned to an Object, String, [Bb]oolean or Class receiver; except null to boolean
-        if (isWildcardLeftHandSide(left) && !(leftRedirect == boolean_TYPE && isNullConstant(rightExpression))) return true;
-
         if (leftRedirect == char_TYPE && rightRedirect == Character_TYPE) return true;
         if (leftRedirect == Character_TYPE && rightRedirect == char_TYPE) return true;
         if ((leftRedirect == char_TYPE || leftRedirect == Character_TYPE) && rightRedirect == STRING_TYPE) {
@@ -727,17 +738,8 @@ public abstract class StaticTypeCheckingSupport {
             return true;
         }
 
-        // simple check on being subclass
-        if (right.isDerivedFrom(left) || (left.isInterface() && right.implementsInterface(left))) return true;
-
-        // if left and right are primitives or numbers allow
-        if (isPrimitiveType(leftRedirect) && isPrimitiveType(rightRedirect)) return true;
-        if (isNumberType(leftRedirect) && isNumberType(rightRedirect)) return true;
-
-        // left is a float/double and right is a BigDecimal
-        if (isFloatingCategory(leftRedirect) && isBigDecimalType(rightRedirect)) {
-            return true;
-        }
+        // simple sub-type check
+        if (!left.isInterface() ? right.isDerivedFrom(left) : GeneralUtils.isOrImplements(right, left)) return true;
 
         if (right.isDerivedFrom(CLOSURE_TYPE) && isSAMType(left)) {
             return true;
diff --git a/src/test/groovy/transform/stc/BugsSTCTest.groovy b/src/test/groovy/transform/stc/BugsSTCTest.groovy
index 7ec25953a8..45f0cd4a91 100644
--- a/src/test/groovy/transform/stc/BugsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/BugsSTCTest.groovy
@@ -1104,15 +1104,10 @@ Printer
 
     // GROOVY-10092
     void testAssignBooleanValueToFloatLocalVariable() {
-        assertScript '''
-            class C {
-                void test() {
-                    float x = true // internal compiler error: Boolean cannot be cast to Number
-                }
-            }
-            //new C().test()
-            'TODO: STC error for incompatible assignment'
-        '''
+        shouldFailWithMessages '''
+            float x = true // internal compiler error: Boolean cannot be cast to Number
+        ''',
+        'Cannot assign value of type boolean to variable of type float'
     }
 
     // GROOVY-10424


[groovy] 01/03: GROOVY-10266: add test case

Posted by em...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit f10d24690aa0a5215ae3d92a2dd16b2f536adfd6
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Wed May 18 10:42:58 2022 -0500

    GROOVY-10266: add test case
---
 src/test/groovy/transform/stc/GenericsSTCTest.groovy | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/src/test/groovy/transform/stc/GenericsSTCTest.groovy b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
index 9e1f53534f..ef29fbb97c 100644
--- a/src/test/groovy/transform/stc/GenericsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
@@ -1317,6 +1317,26 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
+    // GROOVY-10266
+    void testDiamondInferrenceFromConstructor30() {
+        assertScript '''
+            @groovy.transform.TupleConstructor(defaults=false)
+            class A<T> {
+                T t
+            }
+            class B<U> {
+                def m() {
+                    U v = null
+                    U w = new A<>(v).t
+
+                    String x = ""
+                    String y = new A<>(x).t
+                }
+            }
+            new B<String>().m()
+        '''
+    }
+
     // GROOVY-10280
     void testTypeArgumentPropagation() {
         assertScript '''