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 b4b86e6992 GROOVY-11669: SC: support
`ClassLiteral::javaLangClassMethod`
b4b86e6992 is described below
commit b4b86e6992d268096c7b2c87e81d34a9276fdfdb
Author: Eric Milles <[email protected]>
AuthorDate: Sat May 17 23:42:14 2025 -0500
GROOVY-11669: SC: support `ClassLiteral::javaLangClassMethod`
---
...StaticTypesMethodReferenceExpressionWriter.java | 24 ++++++++++++-
.../transform/stc/MethodReferenceTest.groovy | 41 ++++++++++++++++++++--
2 files changed, 62 insertions(+), 3 deletions(-)
diff --git
a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesMethodReferenceExpressionWriter.java
b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesMethodReferenceExpressionWriter.java
index fa7c4d8263..c526caa7b4 100644
---
a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesMethodReferenceExpressionWriter.java
+++
b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesMethodReferenceExpressionWriter.java
@@ -59,6 +59,7 @@ import static
org.codehaus.groovy.ast.tools.GeneralUtils.nullX;
import static org.codehaus.groovy.ast.tools.GeneralUtils.returnS;
import static org.codehaus.groovy.ast.tools.GeneralUtils.varX;
import static org.codehaus.groovy.ast.tools.GenericsUtils.extractPlaceholders;
+import static org.codehaus.groovy.ast.tools.GenericsUtils.makeClassSafe0;
import static org.codehaus.groovy.ast.tools.ParameterUtils.isVargs;
import static
org.codehaus.groovy.ast.tools.ParameterUtils.parametersCompatible;
import static org.codehaus.groovy.runtime.ArrayGroovyMethods.last;
@@ -116,10 +117,16 @@ public class StaticTypesMethodReferenceExpressionWriter
extends MethodReferenceE
Map<MethodNode,MethodNode> bridgeMethods =
typeOrTargetRefType.redirect().getNodeMetaData(StaticCompilationMetadataKeys.PRIVATE_BRIDGE_METHODS);
if (bridgeMethods != null) methodRefMethod =
bridgeMethods.getOrDefault(methodRefMethod, methodRefMethod); // bridge may not
have been generated
}
+ if (methodRefMethod == null && isClassExpression) {
+ var classValue = varX("_class_", typeOrTargetRefType);
+ var classClass = makeClassSafe0(ClassHelper.CLASS_Type, new
GenericsType(typeOrTargetRefType));
+ methodRefMethod = findMethodRefMethod(methodRefName,
parametersWithExactType, classValue, classClass);
+ if (methodRefMethod != null) methodRefMethod =
addSyntheticMethodForClassReference(methodRefMethod, typeOrTargetRefType);
+ }
}
validate(methodReferenceExpression, typeOrTargetRefType,
methodRefName, methodRefMethod, parametersWithExactType,
- resolveClassNodeGenerics(extractPlaceholders(functionalType),
null, abstractMethod.getReturnType()));
+
resolveClassNodeGenerics(extractPlaceholders(functionalType), null,
abstractMethod.getReturnType()));
if (isBridgeMethod(methodRefMethod)) {
targetIsArgument = true; // GROOVY-11301, GROOVY-11365
@@ -242,6 +249,21 @@ public class StaticTypesMethodReferenceExpressionWriter
extends MethodReferenceE
return delegateMethod;
}
+ private MethodNode addSyntheticMethodForClassReference(final MethodNode
mn, final ClassNode classType) {
+ MethodCallExpression methodCall = callX(classX(classType),
mn.getName(), new ArgumentListExpression(mn.getParameters()));
+ methodCall.setImplicitThis(false);
+ methodCall.setMethodTarget(mn);
+
methodCall.putNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET, mn);
+
+ String methodName = "class$" + classType.getNameWithoutPackage() + "$"
+ mn.getName() + "$" + System.nanoTime();
+
+ ClassNode returnType = resolveClassNodeGenerics(Map.of(new
GenericsType.GenericsTypeName("T"), new GenericsType(classType)), null,
mn.getReturnType());
+
+ MethodNode delegateMethod = addSyntheticMethod(methodName, returnType,
methodCall, mn.getParameters(), mn.getExceptions());
+
delegateMethod.putNodeMetaData(StaticCompilationMetadataKeys.STATIC_COMPILE_NODE,
Boolean.TRUE);
+ return delegateMethod;
+ }
+
private MethodNode addSyntheticMethodForVariadicReference(final MethodNode
mn, final int samParameters, final boolean isStaticTarget) {
Parameter[] parameters = new Parameter[samParameters];
Expression arguments, receiver;
diff --git a/src/test/groovy/groovy/transform/stc/MethodReferenceTest.groovy
b/src/test/groovy/groovy/transform/stc/MethodReferenceTest.groovy
index 74288f1eb4..2446bd8093 100644
--- a/src/test/groovy/groovy/transform/stc/MethodReferenceTest.groovy
+++ b/src/test/groovy/groovy/transform/stc/MethodReferenceTest.groovy
@@ -918,6 +918,33 @@ final class MethodReferenceTest {
'''
}
+ // GROOVY-11669
+ @Test // class::classMethod
+ void testFunctionCC1() {
+ assertScript shell, '''
+ @CompileStatic
+ void test() {
+ [1,2,3].stream().map(Number::cast).collect(Collectors.toList())
+ }
+
+ test()
+ '''
+ }
+
+ // GROOVY-11669
+ @Test // class::classMethod
+ void testFunctionCC2() {
+ def err = shouldFail shell, '''
+ @CompileStatic
+ void test() {
+ [1,2,3].stream().map(String::cast).collect(Collectors.toList())
+ }
+
+ test()
+ '''
+ assert err =~ /ClassCastException: Cannot cast java.lang.Integer to
java.lang.String/
+ }
+
@Test // class::new
void testFunctionCN1() {
assertScript shell, '''
@@ -1422,13 +1449,23 @@ final class MethodReferenceTest {
test()
'''
+ assertScript shell, '''
+ @CompileStatic
+ void test() {
+ Supplier<String> s = Object::toString
+ def result = s.get()
+ assert result == 'class java.lang.Object'
+ }
+
+ test()
+ '''
def err = shouldFail shell, '''
@CompileStatic
void test() {
- Supplier<String> s = Object::toString // all options require
an object
+ BinaryOperator<String> s = Object::toString
}
'''
- assert err.message.contains("Failed to find class method 'toString()'
for the type: java.lang.Object")
+ assert err.message.contains("Failed to find class method
'toString(java.lang.String,java.lang.String)' or instance method
'toString(java.lang.String)' for the type: java.lang.Object")
}
// GROOVY-10859