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 20:38:49 UTC

[groovy] branch GROOVY_2_5_X 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 GROOVY_2_5_X
in repository https://gitbox.apache.org/repos/asf/groovy.git


The following commit(s) were added to refs/heads/GROOVY_2_5_X by this push:
     new 78dd65dc1d GROOVY-7247: STC: support spread-map expression
78dd65dc1d is described below

commit 78dd65dc1df3affbd7137a490d1926f1d1e00803
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   | 22 +++++++++----
 .../transform/stc/TypeInferenceSTCTest.groovy      | 36 ++++++++++++++++++++--
 2 files changed, 50 insertions(+), 8 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 cbf76ed566..350341a6f2 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -72,6 +72,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;
@@ -5089,16 +5090,25 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         if (genericsTypes == null
                 || genericsTypes.length < 2
                 || (genericsTypes.length == 2 && OBJECT_TYPE.equals(genericsTypes[0].getType()) && OBJECT_TYPE.equals(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()));
-            }
-            ClassNode keyType = lowestUpperBound(keyTypes);
-            ClassNode valueType = lowestUpperBound(valueTypes);
+                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);
+            }
+            keyType = lowestUpperBound(keyTypes);
+            valueType = lowestUpperBound(valueTypes);
             if (!OBJECT_TYPE.equals(keyType) || !OBJECT_TYPE.equals(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 ac10b0501c..7bf5d8077a 100644
--- a/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy
+++ b/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy
@@ -655,7 +655,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() {
@@ -669,7 +670,38 @@ 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()'
+    }
+
+    // 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 <String, Integer>'
     }
 
     void testFlowTypingWithStringVariable() {