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

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

commit fa0628603cbbced140e49e064a6dee8da9c85a29
Author: Eric Milles <[email protected]>
AuthorDate: Sun Sep 11 10:41:39 2022 -0500

    GROOVY-10107: STC: check assign null before type parameter compatibility
---
 .../java/org/codehaus/groovy/ast/GenericsType.java |  2 +-
 .../codehaus/groovy/ast/tools/GenericsUtils.java   |  2 +-
 .../transform/stc/StaticTypeCheckingSupport.java   | 58 ++++++++++------------
 .../groovy/transform/stc/GenericsSTCTest.groovy    | 12 +++++
 4 files changed, 40 insertions(+), 34 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/ast/GenericsType.java 
b/src/main/java/org/codehaus/groovy/ast/GenericsType.java
index cd123a1a44..75cd9f1458 100644
--- a/src/main/java/org/codehaus/groovy/ast/GenericsType.java
+++ b/src/main/java/org/codehaus/groovy/ast/GenericsType.java
@@ -437,7 +437,7 @@ public class GenericsType extends ASTNode {
                                                 match = 
gt.checkGenerics(classNodeType.getLowerBound());
                                             } else if 
(classNodeType.getUpperBounds() != null) {
                                                 match = 
gt.checkGenerics(classNodeType.getUpperBounds()[0]);
-                                            } else { // GROOVY-10576: "?" vs 
"? extends Object" (citation required) or no match
+                                            } else { // GROOVY-10267, 
GROOVY-10576: "?" vs "? extends Object" (citation required) or no match
                                                 match = (!gt.isPlaceholder() 
&& !gt.isWildcard() && ClassHelper.OBJECT_TYPE.equals(gt.getType()));
                                             }
                                         } else {
diff --git a/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java 
b/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java
index db1a12b1b7..25a4205a19 100644
--- a/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java
+++ b/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java
@@ -173,7 +173,7 @@ public class GenericsUtils {
         GenericsType[] parameterized = type.getGenericsTypes(); int n;
         if (parameterized == null || (n = parameterized.length) == 0) return;
 
-        // GROOVY-8609, GROOVY-10067, etc.
+        // GROOVY-8609
         if (type.isGenericsPlaceHolder()) {
             GenericsType gt = parameterized[0];
             GenericsType.GenericsTypeName name = new 
GenericsType.GenericsTypeName(gt.getName());
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 a1abf7fc8e..10121386a6 100644
--- 
a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
+++ 
b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
@@ -680,44 +680,38 @@ public abstract class StaticTypeCheckingSupport {
     }
 
     public static boolean checkCompatibleAssignmentTypes(ClassNode left, 
ClassNode right, Expression rightExpression, boolean allowConstructorCoercion) {
-        ClassNode leftRedirect = left.redirect();
-        ClassNode rightRedirect = right.redirect();
-        if (leftRedirect == rightRedirect) return true;
+        boolean rightExpressionIsNull = isNullConstant(rightExpression);
+        if (rightExpressionIsNull && !isPrimitiveType(left)) {
+            return true;
+        }
 
-        if (leftRedirect.isArray() && rightRedirect.isArray()) {
-            ClassNode leftComponent = leftRedirect.getComponentType();
-            ClassNode rightComponent = rightRedirect.getComponentType();
+        if (left.isArray() && right.isArray()) {
+            ClassNode leftComponent = left.getComponentType();
+            ClassNode rightComponent = right.getComponentType();
             if (isPrimitiveType(leftComponent) != 
isPrimitiveType(rightComponent)) return false;
             return checkCompatibleAssignmentTypes(leftComponent, 
rightComponent, rightExpression, false);
         }
 
-        if (right == VOID_TYPE || right == void_WRAPPER_TYPE) {
-            return left == VOID_TYPE || left == void_WRAPPER_TYPE;
-        }
+        ClassNode leftRedirect = left.redirect();
+        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 (isNumberType(rightRedirect) || 
WideningCategories.isNumberCategory(rightRedirect)) {
             if (leftRedirect.equals(BigDecimal_TYPE) || 
leftRedirect.equals(Number_TYPE)) {
-                // any number can be assigned to BigDecimal or Number
-                return true;
+                return true; // any number can be assigned to BigDecimal or 
Number
             }
             if (leftRedirect.equals(BigInteger_TYPE)) {
-                return 
WideningCategories.isBigIntCategory(getUnwrapper(rightRedirect)) ||
-                        rightRedirect.isDerivedFrom(BigInteger_TYPE);
+                return 
WideningCategories.isBigIntCategory(getUnwrapper(rightRedirect)) || 
rightRedirect.isDerivedFrom(BigInteger_TYPE);
             }
         }
 
-        // if rightExpression is null and leftExpression is not a primitive 
type, it's ok
-        boolean rightExpressionIsNull = isNullConstant(rightExpression);
-        if (rightExpressionIsNull && !isPrimitiveType(left)) {
-            return true;
-        }
-
         // on an assignment everything that can be done by a GroovyCast is 
allowed
 
-        // anything can be assigned to an Object, String, Boolean
-        // or Class typed variable
-        if (isWildcardLeftHandSide(leftRedirect)
-                && !(left.equals(boolean_TYPE) && rightExpressionIsNull)) 
return true;
+        // anything can be assigned to an Object, String, [Bb]oolean or Class 
receiver; except null to boolean
+        if (isWildcardLeftHandSide(left) && !(leftRedirect == boolean_TYPE && 
rightExpressionIsNull)) return true;
 
         // char as left expression
         if (leftRedirect == char_TYPE && rightRedirect == STRING_TYPE) {
@@ -1829,25 +1823,25 @@ public abstract class StaticTypeCheckingSupport {
     private static void extractGenericsConnections(Map<GenericsTypeName, 
GenericsType> connections, GenericsType[] usage, GenericsType[] declaration) {
         // if declaration does not provide generics, there is no connection to 
make
         if (usage == null || declaration == null || declaration.length == 0) 
return;
-        if (usage.length != declaration.length) return;
+        final int n; if ((n = usage.length) != declaration.length) return;
 
         // both have generics
-        for (int i = 0; i < usage.length; i++) {
+        for (int i = 0; i < n; i += 1) {
             GenericsType ui = usage[i];
             GenericsType di = declaration[i];
             if (di.isPlaceholder()) {
                 connections.put(new GenericsTypeName(di.getName()), ui);
             } else if (di.isWildcard()) {
+                ClassNode lowerBound = di.getLowerBound(), upperBounds[] = 
di.getUpperBounds();
                 if (ui.isWildcard()) {
-                    extractGenericsConnections(connections, 
ui.getLowerBound(), di.getLowerBound());
-                    extractGenericsConnections(connections, 
ui.getUpperBounds(), di.getUpperBounds());
+                    extractGenericsConnections(connections, 
ui.getLowerBound(), lowerBound);
+                    extractGenericsConnections(connections, 
ui.getUpperBounds(), upperBounds);
                 } else {
-                    ClassNode cu = ui.getType();
-                    extractGenericsConnections(connections, cu, 
di.getLowerBound());
-                    ClassNode[] upperBounds = di.getUpperBounds();
+                    ClassNode ui_type = ui.getType();
+                    extractGenericsConnections(connections, ui_type, 
lowerBound);
                     if (upperBounds != null) {
-                        for (ClassNode cn : upperBounds) {
-                            extractGenericsConnections(connections, cu, cn);
+                        for (ClassNode ub : upperBounds) {
+                            extractGenericsConnections(connections, ui_type, 
ub);
                         }
                     }
                 }
diff --git a/src/test/groovy/transform/stc/GenericsSTCTest.groovy 
b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
index 119e4a0c9b..165ca7fd41 100644
--- a/src/test/groovy/transform/stc/GenericsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
@@ -2078,6 +2078,18 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase 
{
         '''
     }
 
+    // GROOVY-10107
+    void testAssignNullTypeParameterWithUpperBounds() {
+        assertScript '''
+            class C<T extends Number> {
+                void m() {
+                    T n = null
+                }
+            }
+            new C<Long>().m()
+        '''
+    }
+
     void testMethodCallWithArgumentUsingNestedGenerics() {
         assertScript '''
            ThreadLocal<Map<Integer, String>> cachedConfigs = new 
ThreadLocal<Map<Integer, String>>()

Reply via email to