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 2023/05/18 15:13:36 UTC

[groovy] branch master updated: GROOVY-10067, GROOVY-11057: better `parameterizeType` result

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 8c9e150087 GROOVY-10067, GROOVY-11057: better `parameterizeType` result
8c9e150087 is described below

commit 8c9e150087484d858e262bd0a5ade5de681d50c4
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Thu May 18 10:09:12 2023 -0500

    GROOVY-10067, GROOVY-11057: better `parameterizeType` result
---
 .../codehaus/groovy/ast/tools/GenericsUtils.java   | 18 +++---
 .../transform/stc/StaticTypeCheckingVisitor.java   | 16 ++---
 .../groovy/ast/tools/GenericsUtilsTest.groovy      | 74 ++++++++++++++++++----
 3 files changed, 81 insertions(+), 27 deletions(-)

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 7b87a7aca1..1572c25915 100644
--- a/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java
+++ b/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java
@@ -442,11 +442,14 @@ public class GenericsUtils {
         return makeClassSafeWithGenerics(type, newgTypes);
     }
 
-    public static ClassNode correctToGenericsSpec(Map<String, ClassNode> genericsSpec, GenericsType type) {
-        ClassNode cn = null; String name = type.getName();
-        if (type.isPlaceholder() && name.charAt(0) != '#') {
-            cn = genericsSpec.get(name);
-        } else if (type.isWildcard()) {
+    public static ClassNode correctToGenericsSpec(final Map<String, ClassNode> genericsSpec, final GenericsType type) {
+        ClassNode cn = null;
+        if (type.isPlaceholder()) {
+            String name = type.getName();
+            if (name.charAt(0) != '#') //
+                cn = genericsSpec.get(name);
+        }
+        else if (type.isWildcard()) {
             if (type.getUpperBounds() != null)
                 cn = type.getUpperBounds()[0]; // GROOVY-9891
         }
@@ -456,7 +459,7 @@ public class GenericsUtils {
         return cn;
     }
 
-    public static ClassNode correctToGenericsSpec(Map<String, ClassNode> genericsSpec, ClassNode type) {
+    public static ClassNode correctToGenericsSpec(final Map<String, ClassNode> genericsSpec, ClassNode type) {
         if (type.isArray()) {
             return correctToGenericsSpec(genericsSpec, type.getComponentType()).makeArray();
         }
@@ -468,8 +471,7 @@ public class GenericsUtils {
                 return correctToGenericsSpec(genericsSpec, type);
             }
         }
-        if (type == null) type = ClassHelper.OBJECT_TYPE.getPlainNodeReference();
-        return type;
+        return type != null ? type : ClassHelper.OBJECT_TYPE.getPlainNodeReference();
     }
 
     public static Map<String, ClassNode> createGenericsSpec(final ClassNode type) {
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 b63f6d9721..825bc16ea8 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -5446,14 +5446,14 @@ out:                if (mn.size() != 1) {
         for (GenericsType gt : methodGenericTypes) {
             // GROOVY-8409, GROOVY-10067, et al.: provide "no type witness" mapping for param
             resolvedPlaceholders.computeIfAbsent(new GenericsTypeName(gt.getName()), gtn -> {
-                GenericsType xxx = new GenericsType(ClassHelper.makeWithoutCaching("#"),
-                        applyGenericsContext(resolvedPlaceholders, gt.getUpperBounds()),
-                        applyGenericsContext(resolvedPlaceholders, gt.getLowerBound()));
-                xxx.getType().setRedirect(getCombinedBoundType(gt));
-                xxx.putNodeMetaData(GenericsType.class, gt);
-                xxx.setName("#" + gt.getName());
-                xxx.setPlaceholder(true);
-                return xxx;
+                ClassNode hash = ClassHelper.makeWithoutCaching("#" + gt.getName());
+                hash.setRedirect(getCombinedBoundType(gt));
+                hash.setGenericsPlaceHolder(true);
+
+                GenericsType gtx = new GenericsType(hash, applyGenericsContext(resolvedPlaceholders, gt.getUpperBounds()), null);
+                gtx.putNodeMetaData(GenericsType.class, gt);
+                gtx.setResolved(true);
+                return gtx;
             });
         }
 
diff --git a/src/test/org/codehaus/groovy/ast/tools/GenericsUtilsTest.groovy b/src/test/org/codehaus/groovy/ast/tools/GenericsUtilsTest.groovy
index 3c72244f59..a1ef582a85 100644
--- a/src/test/org/codehaus/groovy/ast/tools/GenericsUtilsTest.groovy
+++ b/src/test/org/codehaus/groovy/ast/tools/GenericsUtilsTest.groovy
@@ -23,17 +23,18 @@ import org.codehaus.groovy.ast.ClassHelper
 import org.codehaus.groovy.ast.ClassNode
 import org.codehaus.groovy.ast.GenericsType
 import org.codehaus.groovy.control.CompilePhase
+import org.codehaus.groovy.transform.stc.StaticTypeCheckingVisitor
 import org.junit.Test
 
 final class GenericsUtilsTest {
 
     private static List<ClassNode> compile(String code) {
         def compiler = new org.codehaus.groovy.ast.builder.AstStringCompiler()
-        compiler.compile(code, CompilePhase.SEMANTIC_ANALYSIS, false).tail()
+        compiler.compile(code, CompilePhase.INSTRUCTION_SELECTION, false).tail()
     }
 
-    private static ClassNode findClassNode(String name, List<ClassNode> list) {
-        list.find { it.name == name }
+    private static ClassNode findClassNode(String name, classNodes) {
+        classNodes.find { it.name == name }
     }
 
     //--------------------------------------------------------------------------
@@ -177,7 +178,8 @@ final class GenericsUtilsTest {
         assert result.redirect() === target
     }
 
-    @Test // GROOVY-9945
+    // GROOVY-9945
+    @Test
     void testFindParameterizedType8() {
         def classNodeList = compile '''
             interface I<T> {}
@@ -198,7 +200,7 @@ final class GenericsUtilsTest {
             import java.util.function.*
             interface Derived extends BinaryOperator<Integer> {}
         '''
-        ClassNode target = ClassHelper.makeWithoutCaching(java.util.function.BiFunction.class)
+        ClassNode target = ClassHelper.makeWithoutCaching(java.util.function.BiFunction)
         ClassNode source = findClassNode('Derived', classNodeList)
 
         Map<GenericsType, GenericsType> m = GenericsUtils.makeDeclaringAndActualGenericsTypeMapOfExactType(target, source)
@@ -249,7 +251,7 @@ final class GenericsUtilsTest {
             import java.util.function.*
             interface T extends Function<String, Integer> {}
         '''
-        ClassNode samType = findClassNode('T', classNodeList).interfaces.find { it.name == 'java.util.function.Function' }
+        ClassNode samType = findClassNode('java.util.function.Function', findClassNode('T', classNodeList).interfaces)
 
         def typeInfo = GenericsUtils.parameterizeSAM(samType)
 
@@ -265,7 +267,7 @@ final class GenericsUtilsTest {
             import java.util.function.*
             interface T extends BinaryOperator<Integer> {}
         '''
-        ClassNode samType = findClassNode('T', classNodeList).interfaces.find { it.name == 'java.util.function.BinaryOperator' }
+        ClassNode samType = findClassNode('java.util.function.BinaryOperator', findClassNode('T', classNodeList).interfaces)
 
         def typeInfo = GenericsUtils.parameterizeSAM(samType)
 
@@ -276,13 +278,14 @@ final class GenericsUtilsTest {
         assert typeInfo.v2 == ClassHelper.Integer_TYPE
     }
 
-    @Test // GROOVY-10813
+    // GROOVY-10813
+    @Test
     void testParameterizeSAMWithRawType() {
         def classNodeList = compile '''
             interface I extends java.util.function.BinaryOperator {
             }
         '''
-        ClassNode samType = findClassNode('I', classNodeList).interfaces.find { it.name == 'java.util.function.BinaryOperator' }
+        ClassNode samType = findClassNode('java.util.function.BinaryOperator', findClassNode('I', classNodeList).interfaces)
 
         def typeInfo = GenericsUtils.parameterizeSAM(samType)
 
@@ -302,7 +305,7 @@ final class GenericsUtilsTest {
             abstract class A implements I {
             }
         '''
-        ClassNode samType = findClassNode('A', classNodeList).interfaces.find { it.name == 'I' }
+        ClassNode samType = findClassNode('I', findClassNode('A', classNodeList).interfaces)
 
         def typeInfo = GenericsUtils.parameterizeSAM(samType)
 
@@ -321,7 +324,7 @@ final class GenericsUtilsTest {
             abstract class A implements I {
             }
         '''
-        ClassNode samType = findClassNode('A', classNodeList).interfaces.find { it.name == 'I' }
+        ClassNode samType = findClassNode('I', findClassNode('A', classNodeList).interfaces)
 
         def typeInfo = GenericsUtils.parameterizeSAM(samType)
 
@@ -330,4 +333,53 @@ final class GenericsUtilsTest {
 
         assert typeInfo.v2.toString(false) == 'java.lang.CharSequence'
     }
+
+    // GROOVY-10067, GROOVY-11057
+    @Test
+    void testParameterizeType1() {
+        def classNodeList = compile '''
+            @groovy.transform.CompileStatic
+            void test() {
+                def map = [:]
+            }
+        '''
+        // get the intermediate type of the map literal (LinkedHashMap<#K,#V>)
+        def node = classNodeList[0].getDeclaredMethod('test').code.statements[0]
+        def type = new StaticTypeCheckingVisitor(classNodeList[0].module.context,
+                        classNodeList[0]).getType(node.expression.rightExpression)
+
+        ClassNode mapType = GenericsUtils.parameterizeType(type, ClassHelper.MAP_TYPE)
+
+        assert mapType == ClassHelper.MAP_TYPE
+        assert mapType.genericsTypes.length == 2
+        assert mapType.genericsTypes[0].name == '#K'
+        assert mapType.genericsTypes[1].name == '#V'
+        assert mapType.genericsTypes[0].type.unresolvedName == '#K'
+        assert mapType.genericsTypes[1].type.unresolvedName == '#V'
+        assert mapType.genericsTypes[0].type.name == 'java.lang.Object'
+        assert mapType.genericsTypes[1].type.name == 'java.lang.Object'
+    }
+
+    // GROOVY-10067, GROOVY-11057
+    @Test
+    void testParameterizeType2() {
+        def classNodeList = compile '''
+            @groovy.transform.CompileStatic
+            void test() {
+                def list = []
+            }
+        '''
+        // get the intermediate type of the list literal (ArrayList<#E>)
+        def node = classNodeList[0].getDeclaredMethod('test').code.statements[0]
+        def type = new StaticTypeCheckingVisitor(classNodeList[0].module.context,
+                        classNodeList[0]).getType(node.expression.rightExpression)
+
+        ClassNode listType = GenericsUtils.parameterizeType(type, ClassHelper.LIST_TYPE)
+
+        assert listType == ClassHelper.LIST_TYPE
+        assert listType.genericsTypes.length == 1
+        assert listType.genericsTypes[0].name == '#E'
+        assert listType.genericsTypes[0].type.unresolvedName == '#E'
+        assert listType.genericsTypes[0].type.name == 'java.lang.Object'
+    }
 }