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 <[email protected]>
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())
"""
}
}