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/08/18 19:18:40 UTC

[groovy] branch master updated: GROOVY-7247: STC: support spread-map expression

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 437bf26c8e GROOVY-7247: STC: support spread-map expression
437bf26c8e is described below

commit 437bf26c8e9ba9861aed6bd57cf1f0f6dd70b6c5
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Thu Aug 18 14:06:53 2022 -0500

    GROOVY-7247: STC: support spread-map expression
---
 .../transform/stc/StaticTypeCheckingVisitor.java   | 20 ++++++++---
 .../transform/stc/TypeInferenceSTCTest.groovy      | 42 +++++++++++++++++++---
 2 files changed, 53 insertions(+), 9 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 3f7535535c..21069fb39d 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -79,6 +79,7 @@ import org.codehaus.groovy.ast.expr.PrefixExpression;
 import org.codehaus.groovy.ast.expr.PropertyExpression;
 import org.codehaus.groovy.ast.expr.RangeExpression;
 import org.codehaus.groovy.ast.expr.SpreadExpression;
+import org.codehaus.groovy.ast.expr.SpreadMapExpression;
 import org.codehaus.groovy.ast.expr.StaticMethodCallExpression;
 import org.codehaus.groovy.ast.expr.TernaryExpression;
 import org.codehaus.groovy.ast.expr.TupleExpression;
@@ -5300,16 +5301,25 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         if (genericsTypes == null
                 || genericsTypes.length < 2
                 || (genericsTypes.length == 2 && isObjectType(genericsTypes[0].getType()) && isObjectType(genericsTypes[1].getType()))) {
+            ClassNode keyType;
+            ClassNode valueType;
             List<ClassNode> keyTypes = new ArrayList<>(nExpressions);
             List<ClassNode> valueTypes = new ArrayList<>(nExpressions);
             for (MapEntryExpression entryExpression : entryExpressions) {
-                keyTypes.add(getType(entryExpression.getKeyExpression()));
-                valueTypes.add(getType(entryExpression.getValueExpression()));
+                valueType = getType(entryExpression.getValueExpression());
+                if (!(entryExpression.getKeyExpression() instanceof SpreadMapExpression)) {
+                    keyType = getType(entryExpression.getKeyExpression());
+                } else { // GROOVY-7247
+                    valueType = GenericsUtils.parameterizeType(valueType, MAP_TYPE);
+                    keyType = getCombinedBoundType(valueType.getGenericsTypes()[0]);
+                    valueType = getCombinedBoundType(valueType.getGenericsTypes()[1]);
+                }
+                keyTypes.add(keyType);
+                valueTypes.add(valueType);
             }
-            ClassNode keyType = lowestUpperBound(keyTypes);
-            ClassNode valueType = lowestUpperBound(valueTypes);
+            keyType = lowestUpperBound(keyTypes);
+            valueType = lowestUpperBound(valueTypes);
             if (!isObjectType(keyType) || !isObjectType(valueType)) {
-                mapType = mapType.getPlainNodeReference();
                 mapType.setGenericsTypes(new GenericsType[]{new GenericsType(wrapTypeIfNecessary(keyType)), new GenericsType(wrapTypeIfNecessary(valueType))});
             }
         }
diff --git a/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy b/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy
index 372cc054c8..af7526fcb9 100644
--- a/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy
+++ b/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy
@@ -901,7 +901,8 @@ class TypeInferenceSTCTest extends StaticTypeCheckingTestCase {
         shouldFailWithMessages '''
             List values = [x:1,y:2,z:3]*.value
             values*.toUpperCase()
-        ''', 'Cannot find matching method java.lang.Integer#toUpperCase()'
+        ''',
+        'Cannot find matching method java.lang.Integer#toUpperCase()'
     }
 
     void testStarOperatorOnMap3() {
@@ -915,7 +916,8 @@ class TypeInferenceSTCTest extends StaticTypeCheckingTestCase {
         shouldFailWithMessages '''
             def values = [x:1,y:2,z:3]*.value
             values*.toUpperCase()
-        ''', 'Cannot find matching method java.lang.Integer#toUpperCase()'
+        ''',
+        'Cannot find matching method java.lang.Integer#toUpperCase()'
     }
 
     void testStarOperatorOnMap4() {
@@ -943,12 +945,44 @@ class TypeInferenceSTCTest extends StaticTypeCheckingTestCase {
 
         shouldFailWithMessages '''
             [x:1,y:2,z:3]*.value = ""
-        ''', 'Cannot assign java.util.List<java.lang.String> to: java.util.List<java.lang.Integer>'
+        ''',
+        'Cannot assign java.util.List<java.lang.String> to: java.util.List<java.lang.Integer>'
 
         // GROOVY-10326
         shouldFailWithMessages '''
             [x:1,y:2,z:3]*.key = null
-        ''', 'Cannot set read-only property: key'
+        ''',
+        'Cannot set read-only property: key'
+    }
+
+    // GROOVY-7247
+    void testStarOperatorOnMapKey() {
+        assertScript '''
+            Map<String, Integer> map = [*:[A:1], *:[B:2]]
+            assert map == [A:1, B:2]
+        '''
+
+        assertScript '''
+            Map<String, Integer> one = [A:1]
+            Map<String, Integer> two = [B:2]
+            def map = [*:one, *:two]
+            assert map == [A:1, B:2]
+        '''
+
+        assertScript '''
+            @ASTTest(phase=INSTRUCTION_SELECTION, value={
+                def type = node.getNodeMetaData(INFERRED_TYPE)
+                assert type.genericsTypes[0].type == STRING_TYPE
+                assert type.genericsTypes[1].type != Integer_TYPE
+                assert type.genericsTypes[1].type.isDerivedFrom(Number_TYPE)
+            })
+            def map = [*:[A:1], *:[B:2.3]]
+        '''
+
+        shouldFailWithMessages '''
+            Map<String, Integer> map = [*:[A:1], *:[B:2.3]]
+        ''',
+        'Cannot assign java.util.LinkedHashMap<java.lang.String, java.lang.Number',' to: java.util.Map<java.lang.String, java.lang.Integer>'
     }
 
     void testFlowTypingWithStringVariable() {