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

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


The following commit(s) were added to refs/heads/GROOVY_4_0_X by this push:
     new 357a3020ba GROOVY-10067, GROOVY-11057: better `parameterizeType` result
357a3020ba is described below

commit 357a3020bac60dbc8015c251cc26b666459afbb0
Author: Eric Milles <[email protected]>
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 ++---
 .../stc/ArraysAndCollectionsSTCTest.groovy         |  5 +-
 .../groovy/transform/stc/GenericsSTCTest.groovy    | 65 ++++++++++---------
 .../groovy/ast/tools/GenericsUtilsTest.groovy      | 74 ++++++++++++++++++----
 5 files changed, 118 insertions(+), 60 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 ba46f08a07..41b7f6cef8 100644
--- a/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java
+++ b/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java
@@ -443,11 +443,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
         }
@@ -457,7 +460,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();
         }
@@ -469,8 +472,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 93c073a768..67b0e7d083 100644
--- 
a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ 
b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -5437,14 +5437,14 @@ public class StaticTypeCheckingVisitor extends 
ClassCodeVisitorSupport {
         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/groovy/transform/stc/ArraysAndCollectionsSTCTest.groovy 
b/src/test/groovy/transform/stc/ArraysAndCollectionsSTCTest.groovy
index 9f9c14bc89..55eb99243e 100644
--- a/src/test/groovy/transform/stc/ArraysAndCollectionsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/ArraysAndCollectionsSTCTest.groovy
@@ -1103,8 +1103,9 @@ class ArraysAndCollectionsSTCTest extends 
StaticTypeCheckingTestCase {
         'Cannot assign value of type 
groovy.lang.ListWithDefault<java.lang.Integer> to variable of type 
java.util.Set<java.lang.Integer>'
     }
 
+    // GROOVY-8001, GROOVY-11028
     void testMapWithTypeArgumentsInitializedByMapLiteral() {
-        ['CharSequence,Integer', 'String,Number', 'CharSequence,Number'].each 
{ spec ->
+        for (spec in ['CharSequence,Integer', 'String,Number', 
'CharSequence,Number']) {
             assertScript """
                 Map<$spec> map = [a:1,b:2,c:3]
                 assert map.size() == 3
@@ -1113,7 +1114,6 @@ class ArraysAndCollectionsSTCTest extends 
StaticTypeCheckingTestCase {
             """
         }
 
-        // GROOVY-8001
         assertScript '''
             class C {
                 Map<String,Object> map
@@ -1124,7 +1124,6 @@ class ArraysAndCollectionsSTCTest extends 
StaticTypeCheckingTestCase {
             assert c.map['key'] == '42'
         '''
 
-        // GROOVY-11028
         assertScript '''
             Map<String,Integer> map = [:].withDefault { 0 }
             assert map.size() == 0
diff --git a/src/test/groovy/transform/stc/GenericsSTCTest.groovy 
b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
index 8c12bd5226..414792cb1d 100644
--- a/src/test/groovy/transform/stc/GenericsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
@@ -2362,65 +2362,54 @@ class GenericsSTCTest extends 
StaticTypeCheckingTestCase {
             assertScript """
                 $mods void setX(List<String> strings) {
                 }
-                void test() {
-                    x = Collections.emptyList()
-                }
-                test()
+                x = Collections.emptyList()
             """
             assertScript """
                 $mods void setX(Collection<String> strings) {
                 }
-                void test() {
-                    x = Collections.emptyList()
-                }
-                test()
+                x = Collections.emptyList()
             """
             assertScript """
                 $mods void setX(Iterable<String> strings) {
                 }
-                void test() {
-                    x = Collections.emptyList()
-                }
-                test()
+                x = Collections.emptyList()
             """
 
             shouldFailWithMessages """
                 $mods void setX(List<String> strings) {
                 }
-                void test() {
-                    x = Collections.<Integer>emptyList()
-                }
+                x = Collections.<Integer>emptyList()
             """,
             'Incompatible generic argument types. Cannot assign 
java.util.List<java.lang.Integer> to: java.util.List<java.lang.String>'
         }
     }
 
-    // GROOVY-9734, GROOVY-9915
+    // GROOVY-9734, GROOVY-9915, GROOVY-11057
     void testShouldUseMethodGenericType4() {
         for (mods in ['', 'static']) {
             assertScript """
                 $mods void m(List<String> strings) {
                 }
-                void test() {
-                    m(Collections.emptyList())
-                }
-                test()
+                m(Collections.emptyList())
+                m([])
             """
             assertScript """
                 $mods void m(Collection<String> strings) {
                 }
-                void test() {
-                    m(Collections.emptyList())
-                }
-                test()
+                m(Collections.emptyList())
+                m([])
             """
             assertScript """
                 $mods void m(Iterable<String> strings) {
                 }
-                void test() {
-                    m(Collections.emptyList())
+                m(Collections.emptyList())
+                m([])
+            """
+            assertScript """
+                $mods void m(Map<String,Long> mapping) {
                 }
-                test()
+                m(Collections.emptyMap())
+                m([:])
             """
         }
     }
@@ -5261,10 +5250,10 @@ class GenericsSTCTest extends 
StaticTypeCheckingTestCase {
         '''
     }
 
-    // GROOVY-10673
+    // GROOVY-10673, GROOVY-11057
     void testMockito() {
         assertScript '''
-            @Grab('org.mockito:mockito-core:4.5.1')
+            @Grab('org.mockito:mockito-core:4.11.0')
             import static org.mockito.Mockito.*
 
             class C {
@@ -5276,13 +5265,29 @@ class GenericsSTCTest extends 
StaticTypeCheckingTestCase {
 
             def i = mock(I)
             when(i.f(anyString())).thenAnswer { /*InvocationOnMock*/ iom ->
-              //new C(string: iom.arguments[0]) works
+                new C(string: iom.arguments[0])
                 new C().tap {
                     string = iom.arguments[0]
                 }
             }
             assert i.f('x') instanceof C
         '''
+
+        for (map in ['Collections.emptyMap()', '[:]']) {
+            assertScript """
+                @Grab('org.mockito:mockito-core:4.11.0')
+                import static org.mockito.Mockito.*
+
+                interface Configuration {
+                    Map<String,Object> getSettings()
+                }
+
+                def configuration = mock(Configuration).tap {
+                    when(it.getSettings()).thenReturn($map)
+                }
+                assert configuration.settings.isEmpty()
+            """
+        }
     }
 
     
//--------------------------------------------------------------------------
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'
+    }
 }

Reply via email to