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

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


The following commit(s) were added to refs/heads/master by this push:
     new 868dabf  GROOVY-10325: STC: no error for covariant assignment 
`map*.value = x`
868dabf is described below

commit 868dabf9fadbddd13c7e8859556e4ed2796f7e1b
Author: Eric Milles <[email protected]>
AuthorDate: Fri Oct 22 14:29:06 2021 -0500

    GROOVY-10325: STC: no error for covariant assignment `map*.value = x`
    
        Map<String,Object> map = ...
        map.entrySet()[0].value = '' // already works without typecast
---
 .../transform/stc/StaticTypeCheckingVisitor.java   | 25 ++++++++--------
 .../transform/stc/TypeInferenceSTCTest.groovy      | 33 ++++++++++++++++++++++
 2 files changed, 46 insertions(+), 12 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 9c2ce3d..4ab3b0f 100644
--- 
a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ 
b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -224,6 +224,7 @@ import static 
org.codehaus.groovy.ast.tools.GeneralUtils.propX;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.returnS;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.thisPropX;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.varX;
+import static org.codehaus.groovy.ast.tools.GenericsUtils.makeClassSafe0;
 import static 
org.codehaus.groovy.ast.tools.WideningCategories.isBigDecCategory;
 import static 
org.codehaus.groovy.ast.tools.WideningCategories.isBigIntCategory;
 import static org.codehaus.groovy.ast.tools.WideningCategories.isDouble;
@@ -1193,14 +1194,12 @@ public class StaticTypeCheckingVisitor extends 
ClassCodeVisitorSupport {
         return true;
     }
 
-    private ClassNode adjustTypeForSpreading(final ClassNode 
inferredRightExpressionType, final Expression leftExpression) {
-        // imagine we have: list*.foo = 100
-        // then the assignment must be checked against [100], not 100
-        ClassNode wrappedRHS = inferredRightExpressionType;
+    private ClassNode adjustTypeForSpreading(final ClassNode 
rightExpressionType, final Expression leftExpression) {
+        // given "list*.foo = 100" or "map*.value = 100", then the assignment 
must be checked against [100], not 100
         if (leftExpression instanceof PropertyExpression && 
((PropertyExpression) leftExpression).isSpreadSafe()) {
-            wrappedRHS = extension.buildListType(inferredRightExpressionType);
+            return extension.buildListType(rightExpressionType);
         }
-        return wrappedRHS;
+        return rightExpressionType;
     }
 
     private boolean addedReadOnlyPropertyError(final Expression expr) {
@@ -1776,13 +1775,15 @@ public class StaticTypeCheckingVisitor extends 
ClassCodeVisitorSupport {
                 // map*.property syntax acts on Entry
                 switch (pexp.getPropertyAsString()) {
                 case "key":
-                    ClassNode keyList = LIST_TYPE.getPlainNodeReference();
-                    keyList.setGenericsTypes(new GenericsType[]{gts[0]});
-                    return keyList;
+                    return makeClassSafe0(LIST_TYPE, gts[0]);
                 case "value":
-                    ClassNode valueList = LIST_TYPE.getPlainNodeReference();
-                    valueList.setGenericsTypes(new GenericsType[]{gts[1]});
-                    return valueList;
+                    GenericsType v = gts[1];
+                    if (!v.isWildcard()
+                            && !Modifier.isFinal(v.getType().getModifiers())
+                            && 
typeCheckingContext.isTargetOfEnclosingAssignment(pexp)) {
+                        v = GenericsUtils.buildWildcardType(v.getType()); // 
GROOVY-10325
+                    }
+                    return makeClassSafe0(LIST_TYPE, v);
                 default:
                     addStaticTypeError("Spread operator on map only allows one 
of [key,value]", pexp);
                 }
diff --git a/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy 
b/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy
index b5645e0..6d1adfb 100644
--- a/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy
+++ b/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy
@@ -740,6 +740,39 @@ class TypeInferenceSTCTest extends 
StaticTypeCheckingTestCase {
         ''', 'Cannot find matching method java.lang.Integer#toUpperCase()'
     }
 
+    void testStarOperatorOnMap4() {
+        assertScript '''
+            def map = [x:1,y:2,z:3]
+            map*.value = 0
+
+            assert map*.value == [0,0,0]
+        '''
+
+        assertScript '''
+            Map<String,? extends Object> map = [x:1,y:2,z:3]
+            map*.value = 0
+
+            assert map*.value == [0,0,0]
+        '''
+
+        // GROOVY-10325
+        assertScript '''
+            Map<String,Object> map = [x:1,y:2,z:3]
+            map*.value = 0 // was: Cannot assign List<Integer> to List<Object>
+
+            assert map*.value == [0,0,0]
+        '''
+
+        shouldFailWithMessages '''
+            [x:1,y:2,z:3]*.value = ""
+        ''', 'Cannot assign java.util.List<java.lang.String> to: 
java.util.List<java.lang.Integer>'
+
+        def fail = shouldFail '''
+            [x:1,y:2,z:3]*.key = ""
+        '''
+        assert fail == 'Cannot set readonly property: key for class: 
java.util.LinkedHashMap$Entry'
+    }
+
     void testFlowTypingWithStringVariable() {
         // as anything can be assigned to a string, flow typing engine
         // could "erase" the type of the original variable although is must not

Reply via email to