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/01/12 22:30:45 UTC

[groovy] branch GROOVY_2_5_X updated (64fda29773 -> 88545dc97a)

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

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


    from 64fda29773 GROOVY-10339, GROOVY-10633, GROOVY-10890: STC: type parameter resolution
     new 5e9df65c7b GROOVY-10062: STC: combine variadic method return type inference checks
     new 88545dc97a GROOVY-10785: ASM 9.4

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 build.gradle                                       |   2 +-
 .../transform/stc/StaticTypeCheckingVisitor.java   |  21 +-
 .../groovy/transform/stc/GenericsSTCTest.groovy    | 288 ++++++++++++++++++---
 3 files changed, 266 insertions(+), 45 deletions(-)


[groovy] 02/02: GROOVY-10785: ASM 9.4

Posted by em...@apache.org.
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

commit 88545dc97a8e39bcd3fad68a0b09309290f1320e
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Thu Jan 12 16:29:04 2023 -0600

    GROOVY-10785: ASM 9.4
---
 build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/build.gradle b/build.gradle
index 0f186c4331..90b5728149 100644
--- a/build.gradle
+++ b/build.gradle
@@ -143,7 +143,7 @@ configurations {
 
 ext {
     antVersion = '1.9.16'
-    asmVersion = '9.3'
+    asmVersion = '9.4'
     antlrVersion = '2.7.7'
     bridgerVersion = '1.5.Final'
     coberturaVersion = '1.9.4.1'


[groovy] 01/02: GROOVY-10062: STC: combine variadic method return type inference checks

Posted by em...@apache.org.
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

commit 5e9df65c7b9e1a8b6016753820c6809a799f91ff
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Thu Jan 12 15:28:57 2023 -0600

    GROOVY-10062: STC: combine variadic method return type inference checks
    
    2_5_X backport
---
 .../transform/stc/StaticTypeCheckingVisitor.java   |  21 +-
 .../groovy/transform/stc/GenericsSTCTest.groovy    | 288 ++++++++++++++++++---
 2 files changed, 265 insertions(+), 44 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 2824cd95a9..86fecfbf20 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -5306,19 +5306,19 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
                 }
             } else if (nParameters > 0) { // resolve type parameters from call arguments
                 List<Expression> expressions = InvocationWriter.makeArgumentList(arguments).getExpressions();
+                int nArguments = expressions.size();
                 boolean isVargs = isVargs(parameters);
-                if (expressions.size() >= nParameters) {
-                    for (int i = 0; i < nParameters; i += 1) {
+                if (isVargs ? nArguments >= nParameters-1 : nArguments == nParameters) {
+                    for (int i = 0; i < nArguments; i += 1) {
                         if (isNullConstant(expressions.get(i)))
                             continue; // GROOVY-9984: skip null
-                        boolean lastArg = (i == nParameters - 1);
-                        ClassNode paramType = parameters[i].getType();
                         ClassNode argumentType = getDeclaredOrInferredType(expressions.get(i));
-                        while (paramType.isArray() && argumentType.isArray()) {
-                            paramType = paramType.getComponentType();
-                            argumentType = argumentType.getComponentType();
-                        }
-                        if (isUsingGenericsOrIsArrayUsingGenerics(paramType)) {
+                        ClassNode paramType = parameters[Math.min(i, nParameters-1)].getType();
+                        if (GenericsUtils.hasUnresolvedGenerics(paramType)) {
+                            // if supplying array param with multiple arguments or single non-array argument, infer using element type
+                            if (isVargs && (i >= nParameters || (i == nParameters-1 && (nArguments > nParameters || !argumentType.isArray())))) {
+                                paramType = paramType.getComponentType();
+                            }
                             if (argumentType.isDerivedFrom(CLOSURE_TYPE)) {
                                 MethodNode sam = findSAM(paramType);
                                 if (sam != null) { // implicit closure coercion in action!
@@ -5327,9 +5327,6 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
                                                     applyGenericsContextToParameterClass(resolvedPlaceholders, paramType));
                                 }
                             }
-                            if (isVargs && lastArg && paramType.isArray() && !argumentType.isArray()) {
-                                paramType = paramType.getComponentType();
-                            }
                             Map<GenericsTypeName, GenericsType> connections = new HashMap<>();
                             extractGenericsConnections(connections, wrapTypeIfNecessary(argumentType), paramType);
                             for (Map.Entry<GenericsTypeName, GenericsType> connection : connections.entrySet()) {
diff --git a/src/test/groovy/transform/stc/GenericsSTCTest.groovy b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
index 288a74857b..f00d829e74 100644
--- a/src/test/groovy/transform/stc/GenericsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
@@ -172,37 +172,152 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
-    void testReturnTypeInferenceWithMethodGenerics() {
+    void testReturnTypeInferenceWithMethodGenerics1() {
         assertScript '''
-            List<Long> list = Arrays.asList([0L,0L] as Long[])
+            @ASTTest(phase=INSTRUCTION_SELECTION, value={
+                def type = node.getNodeMetaData(INFERRED_TYPE)
+                assert type.toString(false) == 'java.util.List <java.lang.Long>'
+            })
+            def list = Arrays.asList([1L,0L] as Long[])
+            assert list.size() == 2
+            assert list.get(0) == 1
+            assert list.get(1) == 0
+        '''
+
+        assertScript '''
+            @ASTTest(phase=INSTRUCTION_SELECTION, value={
+                def type = node.getNodeMetaData(INFERRED_TYPE)
+                assert type.toString(false) == 'java.util.List <java.lang.Long>'
+            })
+            def list = Arrays.asList(1L,0L)
+            assert list.size() == 2
+            assert list.get(0) == 1
+            assert list.get(1) == 0
+        '''
+
+        assertScript '''
+            @ASTTest(phase=INSTRUCTION_SELECTION, value={
+                def type = node.getNodeMetaData(INFERRED_TYPE)
+                assert type.toString(false) == 'java.util.List <java.lang.Long>'
+            })
+            def list = Arrays.asList(0L)
+            assert list.size() == 1
+            assert list.get(0) == 0
+        '''
+
+        assertScript '''
+            @ASTTest(phase=INSTRUCTION_SELECTION, value={
+                def type = node.getNodeMetaData(INFERRED_TYPE)
+                assert type.toString(false) == 'java.util.List <java.lang.Object>'
+            })
+            def list = Arrays.asList()
+            assert list.size() == 0
         '''
     }
 
-    void testReturnTypeInferenceWithMethodGenericsAndVarArg() {
+    // GROOVY-10062
+    void testReturnTypeInferenceWithMethodGenerics2() {
         assertScript '''
-            List<Long> list = Arrays.asList(0L,0L)
+            def <T> T m(T t, ... zeroOrMore) {
+            }
+
+            @ASTTest(phase=INSTRUCTION_SELECTION, value={
+                def type = node.getNodeMetaData(INFERRED_TYPE)
+                assert type == Integer_TYPE
+            })
+            def obj = m(42)
         '''
     }
 
-    // GROOVY-8638
-    void testReturnTypeInferenceWithMethodGenericsAndBridge() {
+    void testReturnTypeInferenceWithMethodGenerics3() {
+        if (!GroovyAssert.isAtLeastJdk('1.8')) return
+
         assertScript '''
-            @Grab('com.google.guava:guava:19.0')
-            import com.google.common.collect.*
+            Number number = Optional.of(42).get()
+            assert number.intValue() == 42
+        '''
+    }
 
-            ListMultimap<String, Integer> mmap = ArrayListMultimap.create()
+    // GROOVY-9796
+    void testReturnTypeInferenceWithMethodGenerics4() {
+        if (!GroovyAssert.isAtLeastJdk('1.8')) return
 
-            Map<String, Collection<Integer>> map = mmap.asMap()
-            Set<Map.Entry<String, Collection<Integer>>> set = map.entrySet()
-            Iterator<Map.Entry<String, Collection<Integer>>> it = set.iterator()
-            while (it.hasNext()) { Map.Entry<String, Collection<Integer>> entry = it.next()
-                Collection<Integer> values = entry.value
+        shouldFailWithMessages '''
+            Number number = Optional.of(42).orElse(Double.NaN)
+            assert number.intValue() == 42
+        ''',
+        'Cannot find matching method java.util.Optional#orElse(double).'
+    }
+
+    void testReturnTypeInferenceWithMethodGenerics5() {
+        if (!GroovyAssert.isAtLeastJdk('1.8')) return
+
+        assertScript '''
+            Number number = Optional.of((Number) 42).orElse(Double.NaN)
+            assert number.intValue() == 42
+        '''
+    }
+
+    // GROOVY-9796
+    void testReturnTypeInferenceWithMethodGenerics6() {
+        if (!GroovyAssert.isAtLeastJdk('1.8')) return
+
+        shouldFailWithMessages '''
+            Number number = Optional.ofNullable((Integer) null).orElse(42d)
+            assert number.intValue() == 42
+        ''',
+        'Cannot find matching method java.util.Optional#orElse(double).'
+    }
+
+    void testReturnTypeInferenceWithMethodGenerics7() {
+        if (!GroovyAssert.isAtLeastJdk('1.8')) return
+
+        assertScript '''
+            Number number = Optional.<Number>ofNullable((Integer) null).orElse(42d)
+            assert number.intValue() == 42
+        '''
+    }
+
+    // GROOVY-9033
+    void testReturnTypeInferenceWithMethodGenerics8() {
+        shouldFailWithMessages '''
+            List<String> test() {
+              def x = [].each { }
+              x.add(new Object())
+              return x // List<E>
+            }
+        ''',
+        'Incompatible generic argument types.' // Cannot assign java.util.List<java.lang.Object> to: java.util.List<java.lang.String>
+
+        assertScript '''
+            @ASTTest(phase=INSTRUCTION_SELECTION, value={
+                def type = node.getNodeMetaData(INFERRED_TYPE)
+                assert type.genericsTypes[0].toString() == 'java.lang.String'
+                assert type.genericsTypes[1].toString() == 'java.util.List<java.lang.Object>' // not List<E>
+            })
+            def map = [ key: [] ]
+        '''
+    }
+
+    // GROOVY-10049
+    void testReturnTypeInferenceWithMethodGenerics9() {
+        if (!GroovyAssert.isAtLeastJdk('1.8')) return
+
+        assertScript '''
+            def <X> Set<X> f(Class<X> x) {
+                Collections.singleton(x.newInstance(42))
+            }
+            def <T extends Number> List<T> g(Class<T> t) {
+                f(t).stream().filter{n -> n.intValue() > 0}.toList()
             }
+
+            def result = g(Integer)
+            assert result == [ 42 ]
         '''
     }
 
     // GROOVY-10051
-    void testReturnTypeInferenceWithMethodGenericsAndBounds() {
+    void testReturnTypeInferenceWithMethodGenerics10() {
         assertScript '''
             interface Handle {
                 Result getResult()
@@ -236,7 +351,9 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
 
             assert getStrings(null,[]).isEmpty()
         '''
+    }
 
+    void testReturnTypeInferenceWithMethodGenerics1x() {
         assertScript '''
             interface Handle {
                 int getCount()
@@ -264,24 +381,33 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
-    // GROOVY-9033
-    void testReturnTypeInferenceWithMethodGenerics8() {
-        shouldFailWithMessages '''
-            List<String> test() {
-              def x = [].each { }
-              x.add(new Object())
-              return x // List<E>
+    // GROOVY-10067
+    @NotYetImplemented
+    void testReturnTypeInferenceWithMethodGenerics11() {
+        assertScript '''
+            def <N extends Number> N getNumber() {
+                return (N) 42
+            }
+            def f(Integer i) {
+            }
+            def g(int i) {
             }
-        ''',
-        'Incompatible generic argument types.' // Cannot assign java.util.List<java.lang.Object> to: java.util.List<java.lang.String>
 
-        assertScript '''
-            @ASTTest(phase=INSTRUCTION_SELECTION, value={
-                def type = node.getNodeMetaData(INFERRED_TYPE)
-                assert type.genericsTypes[0].toString() == 'java.lang.String'
-                assert type.genericsTypes[1].toString() == 'java.util.List<java.lang.Object>' // not List<E>
-            })
-            def map = [ key: [] ]
+            Integer i = this.<Integer>getNumber()
+            f(this.<Integer>getNumber())
+            g(this.<Integer>getNumber())
+
+            i = (Integer) getNumber()
+            f((Integer) getNumber())
+            g((Integer) getNumber())
+
+            i = getNumber()
+            f(getNumber())
+            g(getNumber())
+
+            i = number
+            f(number)
+            g(number)
         '''
     }
 
@@ -309,6 +435,46 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
+    // GROOVY-8409
+    void testReturnTypeInferenceWithMethodGenerics14() {
+        if (!GroovyAssert.isAtLeastJdk('1.8')) return
+
+        for (t in ['R', 'S', 'T', 'U']) { // BiFunction uses R, T and U
+            assertScript """
+                def <$t> $t applyFunction(java.util.function.BiFunction<Date, URL, $t> action) {
+                    $t result = action.apply(new Date(), new URL('https://www.example.com'))
+                    return result
+                }
+
+                // GroovyCastException: Cannot cast object 'foo' with class 'java.lang.String' to class 'java.util.Date'
+                java.util.function.BiFunction<Date, URL, String> func = { Date d, URL u -> 'foo' }
+                def result = applyFunction(func)
+                assert result == 'foo'
+            """
+        }
+    }
+
+    // GROOVY-8409, GROOVY-10067
+    @NotYetImplemented
+    void testReturnTypeInferenceWithMethodGenerics15() {
+        shouldFailWithMessages '''
+            List<CharSequence> list = ['x'].collect() // GROOVY-10074
+        ''',
+        'Incompatible generic argument types. Cannot assign java.util.List<java.lang.String> to: java.util.List<java.lang.CharSequence>'
+
+        if (!GroovyAssert.isAtLeastJdk('1.8')) return
+
+        shouldFailWithMessages '''
+            List<CharSequence> list = ['x'].stream().toList() // TODO: fix type param bound of StreamGroovyMethods#toList(Stream<T>)
+        ''',
+        'Incompatible generic argument types. Cannot assign java.util.List<java.lang.String> to: java.util.List<java.lang.CharSequence>'
+
+        assertScript '''
+            import static java.util.stream.Collectors.toList
+            List<CharSequence> list = ['x'].stream().collect(toList())
+        '''
+    }
+
     // GROOVY-7316, GROOVY-10256
     void testReturnTypeInferenceWithMethodGenerics16() {
         shouldFailWithMessages '''
@@ -329,7 +495,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
               T p
               T m() {
                 Closure<T> x = { -> p }
-                x() // Cannot return value of type Object on method returning type T
+                x() // Cannot return value of type Object for method returning type T
               }
             }
             assert new C<>(42).m() == 42
@@ -338,6 +504,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
 
     void testReturnTypeInferenceWithMethodGenerics18() {
         if (!GroovyAssert.isAtLeastJdk('1.8')) return
+
         assertScript '''
             @Grab('com.google.guava:guava:31.1-jre')
             import com.google.common.collect.*
@@ -356,6 +523,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     // GROOVY-8638
     void testReturnTypeInferenceWithMethodGenerics18a() {
         if (!GroovyAssert.isAtLeastJdk('1.8')) return
+
         shouldFailWithMessages '''
             @Grab('com.google.guava:guava:31.1-jre')
             import com.google.common.collect.*
@@ -370,6 +538,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     @NotYetImplemented
     void testReturnTypeInferenceWithMethodGenerics18b() {
         if (!GroovyAssert.isAtLeastJdk('1.8')) return
+
         shouldFailWithMessages '''
             @Grab('com.google.guava:guava:31.1-jre')
             import com.google.common.collect.*
@@ -380,6 +549,60 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
         'Cannot assign java.util.Map <String, java.util.Collection> to: java.util.Map <String, Set>'
     }
 
+    // GROOVY-10222
+    void testReturnTypeInferenceWithMethodGenerics19() {
+        assertScript '''
+            class Task {
+                def <T> T exec(args) {
+                    args
+                }
+            }
+            class Test {
+                Task task
+                def <T> T exec(args) {
+                    task.exec(args) // Cannot return value of type #T for method returning T
+                }
+            }
+            String result = new Test(task: new Task()).exec('works')
+            assert result == 'works'
+        '''
+    }
+
+    // GROOVY-9500
+    void testReturnTypeInferenceWithMethodGenerics20() {
+        if (!GroovyAssert.isAtLeastJdk('1.8')) return
+
+        assertScript '''
+            trait Entity<D> {
+            }
+
+            abstract class Path<F extends Entity, T extends Entity> implements Iterable<Path.Segment<F,T>> {
+                interface Segment<F, T> {
+                    F start()
+                    T end()
+                }
+
+                abstract F start()
+                T end() {
+                  end // Cannot return value of type Path$Segment<F,T> for method returning T
+                }
+                T end
+
+                @Override
+                void forEach(java.util.function.Consumer<? super Segment<F, T>> action) {
+                }
+                @Override
+                Spliterator<Segment<F, T>> spliterator() {
+                }
+                @Override
+                Iterator<Segment<F, T>> iterator() {
+                }
+            }
+
+            null
+        '''
+    }
+
     // GROOVY-10339
     @NotYetImplemented
     void testReturnTypeInferenceWithMethodGenerics21() {
@@ -436,6 +659,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     // GROOVY-10589
     void testReturnTypeInferenceWithMethodGenerics25() {
         if (!GroovyAssert.isAtLeastJdk('1.8')) return
+
         String pogo = '''
             @groovy.transform.TupleConstructor
             class Pogo {