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 2025/04/16 15:27:20 UTC

(groovy) 01/01: GROOVY-11621: STC: fix for `list[idx] = null` and `map['key'] = null`

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

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

commit f8cf100ddaee8a7d35f4a5ccaf91741bc635ee42
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Wed Apr 16 09:48:13 2025 -0500

    GROOVY-11621: STC: fix for `list[idx] = null` and `map['key'] = null`
---
 .../transform/stc/StaticTypeCheckingVisitor.java   |  5 +--
 .../stc/ArraysAndCollectionsSTCTest.groovy         | 39 ++++++++++++++++++++++
 2 files changed, 42 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 94dd15e53d..fd1c090078 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -882,12 +882,13 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
                         && enclosingBinaryExpression != null
                         && enclosingBinaryExpression.getLeftExpression() == expression
                         && isAssignment(enclosingBinaryExpression.getOperation().getType())) {
-                    // left hand side of a subscript assignment: map['foo'] = ...
+                    // left hand side of a subscript assignment: map['key'] = ...
                     Expression enclosingExpressionRHS = enclosingBinaryExpression.getRightExpression();
                     if (!(enclosingExpressionRHS instanceof ClosureExpression)) {
                         enclosingExpressionRHS.visit(this);
                     }
-                    ClassNode[] arguments = {rType, getType(enclosingExpressionRHS)};
+                    ClassNode[] arguments = {rType, isNullConstant(enclosingExpressionRHS) // GROOVY-11621
+                                ? UNKNOWN_PARAMETER_TYPE : getType(enclosingExpressionRHS)};
                     List<MethodNode> methods = findMethod(lType, "putAt", arguments);
                     if (methods.isEmpty()) {
                         addNoMatchingMethodError(lType, "putAt", arguments, enclosingBinaryExpression);
diff --git a/src/test/groovy/groovy/transform/stc/ArraysAndCollectionsSTCTest.groovy b/src/test/groovy/groovy/transform/stc/ArraysAndCollectionsSTCTest.groovy
index f21426692e..4ade3f26c6 100644
--- a/src/test/groovy/groovy/transform/stc/ArraysAndCollectionsSTCTest.groovy
+++ b/src/test/groovy/groovy/transform/stc/ArraysAndCollectionsSTCTest.groovy
@@ -945,6 +945,45 @@ class ArraysAndCollectionsSTCTest extends StaticTypeCheckingTestCase {
         'Cannot find matching method java.util.Collection#putAt(int, java.lang.Object)'
     }
 
+    // GROOVY-11621
+    void testListPutAt() {
+        assertScript '''
+            def list = ['a', 'b', 'c']
+            list[0] = 'aa'
+            assert list[0] == 'aa'
+
+            list.set(2, null)
+            assert list[2] == null
+
+            list.putAt(0, null)
+            assert list[0] == null
+
+            list[1] = null
+            assert list[1] == null
+        '''
+    }
+
+    // GROOVY-11621
+    void testMapPutAt() {
+        assertScript '''
+            def map = [a: 'foo', b: 'bar', c: 'baz']
+            map['a'] = 'aa'
+            assert map['a'] == 'aa'
+
+            map.put('c', null)
+            assert map['c'] == null
+
+            map.putAt('a', null)
+            assert map['a'] == null
+
+            map.d = null
+            assert map['d'] == null
+
+            map['b'] = null
+            assert map['b'] == null
+        '''
+    }
+
     // GROOVY-6266
     void testMapGenerics() {
         assertScript '''