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 ec5903b96d GROOVY-9873: use class loader of SAM type for proxy creation
ec5903b96d is described below

commit ec5903b96d041ff3b4d122273fb2b601e88d777d
Author: Eric Milles <eric.mil...@thomsonreuters.com>
AuthorDate: Thu Aug 29 12:32:21 2024 -0500

    GROOVY-9873: use class loader of SAM type for proxy creation
    
    4_0_X backport
---
 .../groovy/vmplugin/v8/TypeTransformers.java       |  21 ++--
 src/test/groovy/bugs/Groovy9873.groovy             | 137 +++++++++++++++++++++
 .../groovy/transform/stc/GenericsSTCTest.groovy    |  10 +-
 3 files changed, 149 insertions(+), 19 deletions(-)

diff --git 
a/src/main/java/org/codehaus/groovy/vmplugin/v8/TypeTransformers.java 
b/src/main/java/org/codehaus/groovy/vmplugin/v8/TypeTransformers.java
index 55c77b65bd..673cc756c0 100644
--- a/src/main/java/org/codehaus/groovy/vmplugin/v8/TypeTransformers.java
+++ b/src/main/java/org/codehaus/groovy/vmplugin/v8/TypeTransformers.java
@@ -141,10 +141,10 @@ public class TypeTransformers {
     }
 
     /**
-     * creates a method handle able to transform the given Closure into a SAM 
type
-     * if the given parameter is a SAM type
+     * Creates a method handle that transforms the given Closure into the given
+     * parameter type, if it is a SAM type.
      */
-    private static MethodHandle createSAMTransform(Object arg, Class<?> 
parameter) {
+    private static MethodHandle createSAMTransform(Object closure, Class<?> 
parameter) {
         Method method = CachedSAMClass.getSAMMethod(parameter);
         if (method == null) return null;
         // TODO: have to think about how to optimize this!
@@ -164,17 +164,14 @@ public class TypeTransformers {
             }
             // the following code will basically do this:
             // return Proxy.newProxyInstance(
-            //        arg.getClass().getClassLoader(),
+            //        parameter.getClassLoader(),
             //        new Class[]{parameter},
-            //        new ConvertedClosure((Closure) arg));
+            //        new ConvertedClosure((Closure)closure, 
method.getName()));
             // TO_REFLECTIVE_PROXY will do that for us, though
             // input is the closure, the method name, the class loader and the
-            // class[]. All of that but the closure must be provided here
+            // class array. All of that but the closure must be provided here.
             MethodHandle ret = TO_REFLECTIVE_PROXY;
-            ret = MethodHandles.insertArguments(ret, 1,
-                    method.getName(),
-                    arg.getClass().getClassLoader(),
-                    new Class[]{parameter});
+            ret = MethodHandles.insertArguments(ret, 1, method.getName(), 
parameter.getClassLoader(), new Class[]{parameter});
             return ret;
         } else {
             // the following code will basically do this:
@@ -207,8 +204,8 @@ public class TypeTransformers {
     }
 
     /**
-     * returns a transformer later applied as filter to transform one
-     * number into another
+     * Returns a transformer later applied as filter to transform one
+     * number into another.
      */
     private static MethodHandle selectNumberTransformer(Class<?> param, Object 
arg) {
         param = TypeHelper.getWrapperClass(param);
diff --git a/src/test/groovy/bugs/Groovy9873.groovy 
b/src/test/groovy/bugs/Groovy9873.groovy
new file mode 100644
index 0000000000..65afad43ed
--- /dev/null
+++ b/src/test/groovy/bugs/Groovy9873.groovy
@@ -0,0 +1,137 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package groovy.bugs
+
+import org.codehaus.groovy.control.CompilerConfiguration
+import org.codehaus.groovy.tools.javac.JavaAwareCompilationUnit
+import org.junit.Test
+
+import static groovy.test.GroovyAssert.assertScript
+
+final class Groovy9873 {
+
+    @Test
+    void testCoerceClosure1() {
+        assertScript '''
+            @Grab('io.vavr:vavr:0.10.4;transitive=false')
+            import io.vavr.control.Try
+            class C { }
+            C resolve() {new C()}
+            Try.of(this::resolve)
+        '''
+    }
+
+    @Test
+    void testCoerceClosure2() {
+        def config = new CompilerConfiguration().tap {
+            jointCompilationOptions = [memStub: true]
+            targetDirectory = File.createTempDir()
+        }
+        File parentDir = File.createTempDir()
+        try {
+            def c = new File(parentDir, 'C.groovy')
+            c.write '''
+                class C<T> {
+                    private T t
+                    C(T item) {
+                        t = item
+                    }
+                    static <U> C<U> of(U item) {
+                        new C<U>(item)
+                    }
+                    def <V> C<V> map(F<? super T, ? super V> func) {
+                        new C<V>(func.apply(t))
+                    }
+                }
+            '''
+            def d = new File(parentDir, 'D.groovy')
+            d.write '''
+                class D {
+                    static <W> Set<W> wrap(W o) {
+                        Collections.singleton(o)
+                    }
+                }
+            '''
+            def f = new File(parentDir, 'F.groovy')
+            f.write '''
+                interface F<X,Y> {
+                    Y apply(X x)
+                }
+            '''
+            def g = new File(parentDir, 'G.groovy')
+            g.write '''
+                def c = C.of(123)
+                def d = c.map(D.&wrap)
+                def e = d.map(x -> x.first().intValue())
+            '''
+
+            def loader = new GroovyClassLoader(this.class.classLoader)
+            def cu = new JavaAwareCompilationUnit(config, loader)
+            cu.addSources(c, d, f, g)
+            cu.compile()
+
+            loader.loadClass('G').main()
+        } finally {
+            parentDir.deleteDir()
+            config.targetDirectory.deleteDir()
+        }
+    }
+
+    @Test
+    void testCoerceClosure3() {
+        def config = new CompilerConfiguration().tap {
+            jointCompilationOptions = [memStub: true]
+            targetDirectory = File.createTempDir()
+        }
+        File parentDir = File.createTempDir()
+        try {
+            def f = new File(parentDir, 'F.groovy')
+            f.write '''
+                class FInfo extends EventObject {
+                    FInfo() { super(null) }
+                }
+                interface FListener extends EventListener {
+                    void somethingHappened(FInfo i)
+                }
+            '''
+            def g = new File(parentDir, 'G.groovy')
+            g.write '''
+                class H {
+                    void addFListener(FListener f) {
+                        f.somethingHappened(null)
+                    }
+                    void removeFListener(FListener f) {
+                    }
+                }
+
+                new H().somethingHappened = { info -> }
+            '''
+
+            def loader = new GroovyClassLoader(this.class.classLoader)
+            def cu = new JavaAwareCompilationUnit(config, loader)
+            cu.addSources(f, g)
+            cu.compile()
+
+            loader.loadClass('G').main()
+        } finally {
+            parentDir.deleteDir()
+            config.targetDirectory.deleteDir()
+        }
+    }
+}
diff --git a/src/test/groovy/transform/stc/GenericsSTCTest.groovy 
b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
index 496ed3571a..31d246e8c6 100644
--- a/src/test/groovy/transform/stc/GenericsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
@@ -2622,13 +2622,9 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase 
{
                     }
                 }
 
-                void test() {
-                    def c = C.of(42)
-                    def d = c.map($toSet)
-                    def e = d.map(x -> x.first().intValue())
-                }
-
-                test()
+                def c = C.of(42)
+                def d = c.map($toSet)
+                def e = d.map(x -> x.first().intValue())
             """
         }
     }

Reply via email to