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 2f31b58af4 GROOVY-9853: SC: method reference to interface abstract / 
default method
2f31b58af4 is described below

commit 2f31b58af40d7889d502b5135a814811e852f7a9
Author: Eric Milles <[email protected]>
AuthorDate: Sat May 21 14:07:09 2022 -0500

    GROOVY-9853: SC: method reference to interface abstract / default method
---
 .../asm/sc/AbstractFunctionalInterfaceWriter.java  | 36 ++++-----
 ...StaticTypesMethodReferenceExpressionWriter.java | 13 +++-
 .../transform/stc/MethodReferenceTest.groovy       | 90 ++++++++++++++++------
 3 files changed, 93 insertions(+), 46 deletions(-)

diff --git 
a/src/main/java/org/codehaus/groovy/classgen/asm/sc/AbstractFunctionalInterfaceWriter.java
 
b/src/main/java/org/codehaus/groovy/classgen/asm/sc/AbstractFunctionalInterfaceWriter.java
index 0223e397ec..d264d19542 100644
--- 
a/src/main/java/org/codehaus/groovy/classgen/asm/sc/AbstractFunctionalInterfaceWriter.java
+++ 
b/src/main/java/org/codehaus/groovy/classgen/asm/sc/AbstractFunctionalInterfaceWriter.java
@@ -30,7 +30,6 @@ import org.objectweb.asm.Opcodes;
 import org.objectweb.asm.Type;
 
 import java.util.Arrays;
-import java.util.LinkedList;
 import java.util.List;
 
 import static org.codehaus.groovy.ast.ClassHelper.getUnwrapper;
@@ -83,28 +82,23 @@ public interface AbstractFunctionalInterfaceWriter {
         );
     }
 
-    default Object[] createBootstrapMethodArguments(String abstractMethodDesc, 
int insn, ClassNode methodOwnerClassNode, MethodNode methodNode, boolean 
serializable) {
-        Parameter[] parameters = 
methodNode.getNodeMetaData(ORIGINAL_PARAMETERS_WITH_EXACT_TYPE);
-        List<Object> argumentList = new LinkedList<>();
-
-        argumentList.add(Type.getType(abstractMethodDesc));
-        argumentList.add(
-                new Handle(
-                        insn,
-                        
BytecodeHelper.getClassInternalName(methodOwnerClassNode.getName()),
-                        methodNode.getName(),
-                        BytecodeHelper.getMethodDescriptor(methodNode),
-                        methodOwnerClassNode.isInterface()
-                )
-        );
-        
argumentList.add(Type.getType(BytecodeHelper.getMethodDescriptor(methodNode.getReturnType(),
 parameters)));
+    default Object[] createBootstrapMethodArguments(final String 
abstractMethodDesc, final int insn, final ClassNode methodOwner, final 
MethodNode methodNode, final boolean serializable) {
+        Object[] arguments = !serializable ? new Object[3] : new 
Object[]{null, null, null, 5, 0};
 
-        if (serializable) {
-            argumentList.add(5);
-            argumentList.add(0);
-        }
+        arguments[0] = Type.getType(abstractMethodDesc);
+
+        arguments[1] = new Handle(
+                insn, // H_INVOKESTATIC or H_INVOKEVIRTUAL or 
H_INVOKEINTERFACE (GROOVY-9853)
+                BytecodeHelper.getClassInternalName(methodOwner.getName()),
+                methodNode.getName(),
+                BytecodeHelper.getMethodDescriptor(methodNode),
+                methodOwner.isInterface());
+
+        arguments[2] = Type.getType(
+                BytecodeHelper.getMethodDescriptor(methodNode.getReturnType(),
+                (Parameter[]) 
methodNode.getNodeMetaData(ORIGINAL_PARAMETERS_WITH_EXACT_TYPE)));
 
-        return argumentList.toArray();
+        return arguments;
     }
 
     default ClassNode convertParameterType(ClassNode targetType, ClassNode 
parameterType, ClassNode inferredType) {
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 222e9ee6fe..aeba6a9ebc 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
@@ -134,14 +134,23 @@ public class StaticTypesMethodReferenceExpressionWriter 
extends MethodReferenceE
             }
         }
 
+        int referenceKind;
+        if (isConstructorReference || methodRefMethod.isStatic()) {
+            referenceKind = Opcodes.H_INVOKESTATIC;
+        } else if (methodRefMethod.getDeclaringClass().isInterface()) {
+            referenceKind = Opcodes.H_INVOKEINTERFACE; // GROOVY-9853
+        } else {
+            referenceKind = Opcodes.H_INVOKEVIRTUAL;
+        }
+
         controller.getMethodVisitor().visitInvokeDynamicInsn(
                 abstractMethod.getName(),
                 createAbstractMethodDesc(functionalInterfaceType, 
typeOrTargetRef),
                 createBootstrapMethod(classNode.isInterface(), false),
                 createBootstrapMethodArguments(
                         abstractMethodDesc,
-                        methodRefMethod.isStatic() || isConstructorReference ? 
Opcodes.H_INVOKESTATIC : Opcodes.H_INVOKEVIRTUAL,
-                        isConstructorReference ? controller.getClassNode() : 
typeOrTargetRefType,
+                        referenceKind,
+                        isConstructorReference ? classNode : 
typeOrTargetRefType,
                         methodRefMethod,
                         false
                 )
diff --git a/src/test/groovy/transform/stc/MethodReferenceTest.groovy 
b/src/test/groovy/transform/stc/MethodReferenceTest.groovy
index da8a61f2bf..b73012ba40 100644
--- a/src/test/groovy/transform/stc/MethodReferenceTest.groovy
+++ b/src/test/groovy/transform/stc/MethodReferenceTest.groovy
@@ -18,8 +18,6 @@
  */
 package groovy.transform.stc
 
-import org.codehaus.groovy.control.CompilerConfiguration
-import org.codehaus.groovy.control.customizers.ImportCustomizer
 import org.junit.Test
 
 import static groovy.test.GroovyAssert.assertScript
@@ -27,10 +25,13 @@ import static groovy.test.GroovyAssert.shouldFail
 
 final class MethodReferenceTest {
 
-    private final GroovyShell shell = new GroovyShell(new 
CompilerConfiguration().tap {
-        addCompilationCustomizers(new 
ImportCustomizer().addStarImports('java.util.function')
-                .addImports('java.util.stream.Collectors', 
'groovy.transform.CompileStatic'))
-    })
+    private final GroovyShell shell = GroovyShell.withConfig {
+        imports {
+            normal 'groovy.transform.CompileStatic'
+            normal 'java.util.stream.Collectors'
+            star 'java.util.function'
+        }
+    }
 
     @Test // class::instanceMethod
     void testFunctionCI() {
@@ -61,13 +62,11 @@ final class MethodReferenceTest {
     @Test // class::instanceMethod -- GROOVY-10047
     void testFunctionCI3() {
         assertScript shell, '''
-            import static java.util.stream.Collectors.toMap
-
             @CompileStatic
             void p() {
                 List<String> list = ['a','bc','def']
                 Function<String,String> self = str -> str // help for toMap
-                def map = list.stream().collect(toMap(self, String::length))
+                def map = list.stream().collect(Collectors.toMap(self, 
String::length))
                 assert map == [a: 1, bc: 2, 'def': 3]
             }
 
@@ -75,13 +74,11 @@ final class MethodReferenceTest {
         '''
 
         assertScript shell, '''
-            import static java.util.stream.Collectors.toMap
-
             @CompileStatic
             void p() {
                 List<String> list = ['a','bc','def']
                 // TODO: inference for T in toMap(Function<? super T,...>, 
Function<? super T,...>)
-                def map = 
list.stream().collect(toMap(Function.<String>identity(), String::length))
+                def map = 
list.stream().collect(Collectors.toMap(Function.<String>identity(), 
String::length))
                 assert map == [a: 1, bc: 2, 'def': 3]
             }
 
@@ -99,7 +96,6 @@ final class MethodReferenceTest {
 
             p()
         '''
-
         assert err =~ /Invalid receiver type: java.lang.Integer is not 
compatible with java.lang.String/
     }
 
@@ -129,6 +125,61 @@ final class MethodReferenceTest {
         '''
     }
 
+    @Test // class::instanceMethod -- GROOVY-9853
+    void testFunctionCI6() {
+        assertScript shell, '''
+            @CompileStatic
+            void test() {
+                ToIntFunction<CharSequence> f = CharSequence::size
+                int size = f.applyAsInt("")
+                assert size == 0
+            }
+            test()
+        '''
+
+        assertScript shell, '''
+            @CompileStatic
+            void test() {
+                ToIntFunction<CharSequence> f = CharSequence::length
+                int length = f.applyAsInt("")
+                assert length == 0
+            }
+            test()
+        '''
+
+        assertScript shell, '''
+            @CompileStatic
+            void test() {
+                Function<CharSequence,Integer> f = CharSequence::length
+                Integer length = f.apply("")
+                assert length == 0
+            }
+            test()
+        '''
+
+        assertScript shell, '''
+            import java.util.stream.IntStream
+
+            @CompileStatic
+            void test() {
+                Function<CharSequence,IntStream> f = CharSequence::chars // 
default method
+                IntStream chars = f.apply("")
+                assert chars.count() == 0
+            }
+            test()
+        '''
+
+        assertScript shell, '''
+            @CompileStatic
+            void test() {
+                ToIntBiFunction<CharSequence,CharSequence> f = 
CharSequence::compare // static method
+                int result = f.applyAsInt("","")
+                assert result == 0
+            }
+            test()
+        '''
+    }
+
     @Test // class::instanceMethod -- GROOVY-9974
     void testPredicateCI() {
         assertScript shell, '''
@@ -145,12 +196,11 @@ final class MethodReferenceTest {
     void testBinaryOperatorCI() {
         assertScript shell, '''
             @CompileStatic
-            void p() {
+            void test() {
                 def result = [1.0G, 2.0G, 3.0G].stream().reduce(0.0G, 
BigDecimal::add)
                 assert 6.0G == result
             }
-
-            p()
+            test()
         '''
     }
 
@@ -456,12 +506,10 @@ final class MethodReferenceTest {
     @Test // class::staticMethod
     void testFunctionCS2() {
         assertScript shell, '''
-            import static java.util.stream.Collectors.toMap
-
             @CompileStatic
             void p() {
                 List<String> list = ['x','y','z']
-                def map = list.stream().collect(toMap(Function.identity(), 
Collections::singletonList))
+                def map = 
list.stream().collect(Collectors.toMap(Function.identity(), 
Collections::singletonList))
                 assert map == [x: ['x'], y: ['y'], z: ['z']]
             }
 
@@ -611,7 +659,6 @@ final class MethodReferenceTest {
                 [1.0G, 2.0G, 3.0G].stream().reduce(0.0G, BigDecimal::addx)
             }
         '''
-
         assert err.message.contains('Failed to find the expected 
method[addx(java.math.BigDecimal,java.math.BigDecimal)] in the 
type[java.math.BigDecimal]')
     }
 
@@ -623,7 +670,6 @@ final class MethodReferenceTest {
                 Function<String,String> reference = String::toLowerCaseX
             }
         '''
-
         assert err.message.contains('Failed to find the expected 
method[toLowerCaseX(java.lang.String)] in the type[java.lang.String]')
     }
 
@@ -641,7 +687,6 @@ final class MethodReferenceTest {
                 baz(this::foo) // not yet supported!
             }
         '''
-
         assert err =~ /The argument is a method reference, but the parameter 
type is not a functional interface/
     }
 
@@ -659,7 +704,6 @@ final class MethodReferenceTest {
                 }
             }
         '''
-
         assert err =~ /The argument is a method reference, but the parameter 
type is not a functional interface/
     }
 }

Reply via email to