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 2021/05/18 19:35:37 UTC

[groovy] branch master updated: GROOVY-8310, GROOVY-10091: STC: allow simple covariace of closure return

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 f3d030a  GROOVY-8310, GROOVY-10091: STC: allow simple covariace of closure return
f3d030a is described below

commit f3d030afaaae44eca567ead74e68efb932831b08
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Tue May 18 13:06:27 2021 -0500

    GROOVY-8310, GROOVY-10091: STC: allow simple covariace of closure return
---
 .../transform/stc/StaticTypeCheckingVisitor.java   |  8 ++---
 src/test/groovy/bugs/Groovy8310.groovy             | 39 ++++++++++------------
 .../groovy/transform/stc/ClosuresSTCTest.groovy    | 26 +++++++++++++--
 3 files changed, 45 insertions(+), 28 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 4c2cdf6..a0edd33 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -2207,10 +2207,10 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
             }
             if (isStringType(inferredReturnType) && isGStringOrGStringStringLUB(type)) {
                 type = STRING_TYPE; // GROOVY-9971: convert GString to String at point of return
-            } else if (inferredReturnType != null && !inferredReturnType.isGenericsPlaceHolder()
-                    && !type.isUsingGenerics() && !type.equals(inferredReturnType) && (inferredReturnType.isInterface()
-                            ? type.implementsInterface(inferredReturnType) : type.isDerivedFrom(inferredReturnType))) {
-                type = inferredReturnType; // GROOVY-10082: allow simple covariance
+            } else if (inferredReturnType != null
+                    && !GenericsUtils.hasUnresolvedGenerics(inferredReturnType)
+                    &&  GenericsUtils.buildWildcardType(inferredReturnType).isCompatibleWith(type)) {
+                type = inferredReturnType; // GROOVY-8310, GROOVY-10082, GROOVY-10091: allow simple covariance
             }
             return type;
         }
diff --git a/src/test/groovy/bugs/Groovy8310.groovy b/src/test/groovy/bugs/Groovy8310.groovy
index d6e4116..14ba764 100644
--- a/src/test/groovy/bugs/Groovy8310.groovy
+++ b/src/test/groovy/bugs/Groovy8310.groovy
@@ -18,101 +18,98 @@
  */
 package groovy.bugs
 
-import groovy.transform.CompileStatic
 import org.junit.Test
 
 import static groovy.test.GroovyAssert.assertScript
-import static groovy.test.GroovyAssert.shouldFail
 
-@CompileStatic
 final class Groovy8310 {
 
     @Test
     void testClosureReturnType1() {
-        def err = shouldFail '''
+        assertScript '''
             def bar(Closure<Collection<Integer>> block) {
                 block()
             }
 
             @groovy.transform.CompileStatic
-            def use() {
+            def foo() {
                 bar {
                     [1]
                 }
             }
-        '''
 
-        assert err =~ /Cannot find matching method \w+#bar\(groovy.lang.Closure<java.util.List<java.lang.Integer>>\)/
+            assert foo() == [1]
+        '''
     }
 
     @Test
     void testClosureReturnType2() {
-        def err = shouldFail '''
-            public <T> T bar(Closure<Collection<Integer>> block) {
+        assertScript '''
+            def <T> T bar(Closure<Collection<Integer>> block) {
                 block()
             }
 
             @groovy.transform.CompileStatic
-            def use() {
+            def foo() {
                 bar {
                     [1]
                 }
             }
-        '''
 
-        assert err =~ /Cannot call <T> \w+#bar\(groovy.lang.Closure<java.util.Collection<java.lang.Integer>>\) with arguments \[groovy.lang.Closure<java.util.List<java.lang.Integer>>\]/
+            assert foo() == [1]
+        '''
     }
 
     @Test
     void testClosureReturnType3() {
         assertScript '''
-            public <T> T bar(Closure<? extends Collection<Integer>> block) {
+            def <T> T bar(Closure<? extends Collection<Integer>> block) {
                 block()
             }
 
             @groovy.transform.CompileStatic
-            def use() {
+            def foo() {
                 bar {
                     [1]
                 }
             }
 
-            assert use() == [1]
+            assert foo() == [1]
         '''
     }
 
     @Test
     void testClosureReturnType4() {
         assertScript '''
-            public <T> T bar(Closure<Collection<Integer>> block) {
+            def <T> T bar(Closure<Collection<Integer>> block) {
                 block()
             }
 
             @groovy.transform.CompileStatic
-            def use() {
+            def foo() {
                 bar {
                     (Collection<Integer>) [1]
                 }
             }
 
-            assert use() == [1]
+            assert foo() == [1]
         '''
     }
 
     @Test
     void testClosureReturnType5() {
         assertScript '''
-            public <T> T bar(Closure<Collection<Integer>> block) {
+            def <T> T bar(Closure<Collection<Integer>> block) {
                 block()
             }
 
-            def use() {
+            def foo() {
                 bar {
                     [1] as Collection<Integer>
                 }
             }
 
-            assert use() == [1]
+            assert foo() == [1]
         '''
     }
 }
diff --git a/src/test/groovy/transform/stc/ClosuresSTCTest.groovy b/src/test/groovy/transform/stc/ClosuresSTCTest.groovy
index 4024fc3..437c63e 100644
--- a/src/test/groovy/transform/stc/ClosuresSTCTest.groovy
+++ b/src/test/groovy/transform/stc/ClosuresSTCTest.groovy
@@ -165,16 +165,36 @@ class ClosuresSTCTest extends StaticTypeCheckingTestCase {
         assertScript '''
             class A {}
             class B extends A {}
-            Closure<A> c = { -> new B() } // Cannot assign Closure<B> to Closure<A>
+            Closure<A> c = { -> new B() }
 
             def result = c()
             assert result instanceof A
             assert result instanceof B
         '''
+        shouldFailWithMessages '''
+            Closure<String> c = { -> 42 }
+        ''',
+        'Cannot assign groovy.lang.Closure<java.lang.Integer> to: groovy.lang.Closure<java.lang.String>'
     }
 
-    // GROOVY-8427
+    // GROOVY-10091
     void testClosureReturnTypeInference7() {
+        shouldFailWithMessages '''
+            class A<T> {}
+            class B extends A<Number> {}
+            class X extends A<String> {}
+            class Y<Z> extends A<Number> {}
+
+            Closure<A<Number>> c
+            c = { -> return new B() }
+            c = { -> return new X() }
+            c = { -> return new Y<String>() }
+        ''',
+        'Cannot assign groovy.lang.Closure<X> to: groovy.lang.Closure<A<java.lang.Number>>'
+    }
+
+    // GROOVY-8427
+    void testClosureReturnTypeInference8() {
         assertScript '''
             import java.util.function.Consumer
 
@@ -196,7 +216,7 @@ class ClosuresSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-8202
-    void testClosureReturnTypeInference8() {
+    void testClosureReturnTypeInference9() {
         assertScript '''
             void proc() {
             }