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 2022/05/28 18:40:00 UTC

[groovy] branch master updated: GROOVY-9813: SC: match functional interface to variadic method reference

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 2b6db817e3 GROOVY-9813: SC: match functional interface to variadic method reference
2b6db817e3 is described below

commit 2b6db817e3c12fea5d028d6a0bc984a91b7119b2
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Sat May 28 13:25:54 2022 -0500

    GROOVY-9813: SC: match functional interface to variadic method reference
---
 .../codehaus/groovy/ast/tools/ParameterUtils.java  |   8 +
 .../groovy/classgen/AsmClassGenerator.java         |   5 +-
 ...StaticTypesMethodReferenceExpressionWriter.java | 180 +++++++++++++++------
 .../transform/stc/StaticTypeCheckingSupport.java   |   4 +-
 .../transform/stc/MethodReferenceTest.groovy       | 105 +++++++++---
 5 files changed, 224 insertions(+), 78 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/ast/tools/ParameterUtils.java b/src/main/java/org/codehaus/groovy/ast/tools/ParameterUtils.java
index 372c4aa3f3..a7db7d998c 100644
--- a/src/main/java/org/codehaus/groovy/ast/tools/ParameterUtils.java
+++ b/src/main/java/org/codehaus/groovy/ast/tools/ParameterUtils.java
@@ -27,6 +27,14 @@ import java.util.function.BiPredicate;
 
 public class ParameterUtils {
 
+    /**
+     * @since 5.0.0
+     */
+    public static boolean isVargs(final Parameter[] parameters) {
+        if (parameters == null || parameters.length == 0) return false;
+        return (parameters[parameters.length - 1].getType().isArray());
+    }
+
     public static boolean parametersEqual(final Parameter[] a, final Parameter[] b) {
         return parametersEqual(a, b, false);
     }
diff --git a/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java b/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java
index e949dc3415..d9947b1ad5 100644
--- a/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java
+++ b/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java
@@ -154,6 +154,7 @@ import static org.codehaus.groovy.ast.tools.GeneralUtils.fieldX;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.maybeFallsThrough;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.propX;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.thisPropX;
+import static org.codehaus.groovy.ast.tools.ParameterUtils.isVargs;
 import static org.codehaus.groovy.transform.SealedASTTransformation.sealedNative;
 import static org.codehaus.groovy.transform.SealedASTTransformation.sealedSkipAnnotation;
 import static org.codehaus.groovy.transform.sc.StaticCompilationMetadataKeys.PROPERTY_OWNER;
@@ -2323,10 +2324,6 @@ public class AsmClassGenerator extends ClassGenerator {
         return ExpressionUtils.isNullConstant(expression);
     }
 
-    private static boolean isVargs(final Parameter[] parameters) {
-        return (parameters.length > 0 && parameters[parameters.length - 1].getType().isArray());
-    }
-
     private void loadThis(final VariableExpression thisOrSuper) {
         MethodVisitor mv = controller.getMethodVisitor();
         mv.visitVarInsn(ALOAD, 0);
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 4c5b44fff1..8a13ac663d 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
@@ -46,15 +46,15 @@ import java.util.Arrays;
 import java.util.List;
 import java.util.stream.Collectors;
 
-import static org.apache.groovy.ast.tools.ClassNodeUtils.addGeneratedMethod;
-import static org.codehaus.groovy.ast.tools.GeneralUtils.args;
-import static org.codehaus.groovy.ast.tools.GeneralUtils.block;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.callX;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.classX;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.ctorX;
 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.ParameterUtils.isVargs;
 import static org.codehaus.groovy.ast.tools.ParameterUtils.parametersCompatible;
+import static org.codehaus.groovy.runtime.DefaultGroovyMethods.last;
 import static org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.filterMethodsByVisibility;
 import static org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.findDGMMethodsForClassNode;
 import static org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.isAssignableTo;
@@ -111,15 +111,23 @@ public class StaticTypesMethodReferenceExpressionWriter extends MethodReferenceE
             if (extensionMethodNode.isStaticExtension()) {
                 methodRefMethod = addSyntheticMethodForDGSM(methodRefMethod);
             }
-
-            typeOrTargetRefType = methodRefMethod.getDeclaringClass();
-            Expression classExpression = classX(typeOrTargetRefType);
-            classExpression.setSourcePosition(typeOrTargetRef);
-            typeOrTargetRef = classExpression;
+            typeOrTargetRef = makeClassTarget(methodRefMethod.getDeclaringClass(), typeOrTargetRef);
+            typeOrTargetRefType = typeOrTargetRef.getType();
+
+        } else if (isVargs(methodRefMethod.getParameters())) {
+            int mParameters = abstractMethod.getParameters().length;
+            int nParameters = methodRefMethod.getParameters().length;
+            if (isTypeReferringInstanceMethod(typeOrTargetRef, methodRefMethod)) nParameters += 1;
+            if (mParameters > nParameters || mParameters == nParameters-1 || (mParameters == nParameters
+                    && !isAssignableTo(last(parametersWithExactType).getType(), last(methodRefMethod.getParameters()).getType()))) {
+                methodRefMethod = addSyntheticMethodForVariadicReference(methodRefMethod, mParameters, isClassExpression); // GROOVY-9813
+                if (methodRefMethod.isStatic()) {
+                    typeOrTargetRef = makeClassTarget(methodRefMethod.getDeclaringClass(), typeOrTargetRef);
+                    typeOrTargetRefType = typeOrTargetRef.getType();
+                }
+            }
         }
 
-        methodRefMethod.putNodeMetaData(ORIGINAL_PARAMETERS_WITH_EXACT_TYPE, parametersWithExactType);
-
         if (!isClassExpression) {
             if (isConstructorReference) {
                 // TODO: move the checking code to the parser
@@ -143,18 +151,23 @@ public class StaticTypesMethodReferenceExpressionWriter extends MethodReferenceE
             referenceKind = Opcodes.H_INVOKEVIRTUAL;
         }
 
-        controller.getMethodVisitor().visitInvokeDynamicInsn(
-                abstractMethod.getName(),
-                createAbstractMethodDesc(functionalInterfaceType, typeOrTargetRef),
-                createBootstrapMethod(classNode.isInterface(), false),
-                createBootstrapMethodArguments(
-                        abstractMethodDesc,
-                        referenceKind,
-                        isConstructorReference ? classNode : typeOrTargetRefType,
-                        methodRefMethod,
-                        false
-                )
-        );
+        methodRefMethod.putNodeMetaData(ORIGINAL_PARAMETERS_WITH_EXACT_TYPE, parametersWithExactType);
+        try {
+            controller.getMethodVisitor().visitInvokeDynamicInsn(
+                    abstractMethod.getName(),
+                    createAbstractMethodDesc(functionalInterfaceType, typeOrTargetRef),
+                    createBootstrapMethod(classNode.isInterface(), false),
+                    createBootstrapMethodArguments(
+                            abstractMethodDesc,
+                            referenceKind,
+                            isConstructorReference ? classNode : typeOrTargetRefType,
+                            methodRefMethod,
+                            false
+                    )
+            );
+        } finally {
+            methodRefMethod.removeNodeMetaData(ORIGINAL_PARAMETERS_WITH_EXACT_TYPE);
+        }
 
         if (isClassExpression) {
             controller.getOperandStack().push(redirect);
@@ -181,29 +194,64 @@ public class StaticTypesMethodReferenceExpressionWriter extends MethodReferenceE
 
     private MethodNode addSyntheticMethodForDGSM(final MethodNode mn) {
         Parameter[] parameters = removeFirstParameter(mn.getParameters());
-        ArgumentListExpression args = args(parameters);
+        ArgumentListExpression args = new ArgumentListExpression(parameters);
         args.getExpressions().add(0, nullX());
 
-        MethodCallExpression returnValue = callX(classX(mn.getDeclaringClass()), mn.getName(), args);
-        returnValue.putNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET, mn);
-        returnValue.setMethodTarget(mn);
+        MethodCallExpression methodCall = callX(classX(mn.getDeclaringClass()), mn.getName(), args);
+        methodCall.setImplicitThis(false);
+        methodCall.setMethodTarget(mn);
+        methodCall.putNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET, mn);
 
-        MethodNode delegateMethod = addGeneratedMethod(controller.getClassNode(),
-                "dgsm$$" + mn.getParameters()[0].getType().getName().replace('.', '$') + "$$" + mn.getName(),
-                Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC | Opcodes.ACC_FINAL | Opcodes.ACC_SYNTHETIC,
-                mn.getReturnType(),
-                parameters,
-                ClassNode.EMPTY_ARRAY,
-                block(returnS(returnValue))
-        );
+        String methodName = "dgsm$$" + mn.getParameters()[0].getType().getName().replace('.', '$') + "$$" + mn.getName();
 
+        MethodNode delegateMethod = addSyntheticMethod(methodName, mn.getReturnType(), methodCall, parameters, 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 = null, receiver = null;
+        if (mn.isStatic()) {
+            for (int i = 0, j = mn.getParameters().length-1; i < samParameters; i += 1) {
+                ClassNode t = mn.getParameters()[Math.min(i, j)].getType();
+                if (i >= j) t = t.getComponentType(); // targets the array
+                parameters[i] = new Parameter(t, "p" + i);
+            }
+            arguments = new ArgumentListExpression(parameters);
+            receiver = classX(mn.getDeclaringClass());
+        } else {
+            int p = 0;
+            if (isStaticTarget) parameters[p++] = new Parameter(mn.getDeclaringClass(), "o");
+            for (int i = 0, j = mn.getParameters().length-1; i < samParameters - p; i += 1) {
+                ClassNode t = mn.getParameters()[Math.min(i, j)].getType();
+                if (i >= j) t = t.getComponentType(); // targets the array
+                parameters[p++] = new Parameter(t, "p" + p);
+            }
+            if (isStaticTarget) {
+                arguments = new ArgumentListExpression(removeFirstParameter(parameters));
+                receiver = varX(parameters[0]);
+            } else {
+                arguments = new ArgumentListExpression(parameters);
+                receiver = varX("this", controller.getClassNode());
+            }
+        }
+
+        MethodCallExpression methodCall = callX(receiver, mn.getName(), arguments);
+        methodCall.setImplicitThis(false);
+        methodCall.setMethodTarget(mn);
+        methodCall.putNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET, mn);
 
+        String methodName = "adapt$" + mn.getDeclaringClass().getNameWithoutPackage() + "$" + mn.getName() + "$" + System.nanoTime();
+
+        MethodNode delegateMethod = addSyntheticMethod(methodName, mn.getReturnType(), methodCall, parameters, mn.getExceptions());
+        if (!isStaticTarget && !mn.isStatic()) delegateMethod.setModifiers(delegateMethod.getModifiers() & ~Opcodes.ACC_STATIC);
+        delegateMethod.putNodeMetaData(StaticCompilationMetadataKeys.STATIC_COMPILE_NODE, Boolean.TRUE);
         return delegateMethod;
     }
 
-    private MethodNode addSyntheticMethodForConstructorReference(final String syntheticMethodName, final ClassNode returnType, final Parameter[] parametersWithExactType) {
-        ArgumentListExpression ctorArgs = args(parametersWithExactType);
+    private MethodNode addSyntheticMethodForConstructorReference(final String methodName, final ClassNode returnType, final Parameter[] parametersWithExactType) {
+        ArgumentListExpression ctorArgs = new ArgumentListExpression(parametersWithExactType);
 
         Expression returnValue;
         if (returnType.isArray()) {
@@ -214,23 +262,24 @@ public class StaticTypesMethodReferenceExpressionWriter extends MethodReferenceE
             returnValue = ctorX(returnType, ctorArgs);
         }
 
-        MethodNode delegateMethod = addGeneratedMethod(controller.getClassNode(),
-                syntheticMethodName,
-                Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC | Opcodes.ACC_FINAL | Opcodes.ACC_SYNTHETIC,
-                returnType,
-                parametersWithExactType,
-                ClassNode.EMPTY_ARRAY,
-                block(returnS(returnValue))
-        );
-
+        MethodNode delegateMethod = addSyntheticMethod(methodName, returnType, returnValue, parametersWithExactType, ClassNode.EMPTY_ARRAY);
         // TODO: if StaticTypesMarker.DIRECT_METHOD_CALL_TARGET or
         // OptimizingStatementWriter.StatementMeta.class metadatas
         // can bet set for the ctorX above, then this can be TRUE:
         delegateMethod.putNodeMetaData(StaticCompilationMetadataKeys.STATIC_COMPILE_NODE, Boolean.FALSE);
-
         return delegateMethod;
     }
 
+    private MethodNode addSyntheticMethod(final String methodName, final ClassNode returnType, final Expression returnValue, final Parameter[] parameters, final ClassNode[] exceptions) {
+        return controller.getClassNode().addSyntheticMethod(
+            methodName,
+            Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC | Opcodes.ACC_FINAL,
+            returnType,
+            parameters,
+            exceptions,
+            returnS(returnValue));
+    }
+
     private String createAbstractMethodDesc(final ClassNode functionalInterfaceType, final Expression methodRef) {
         List<Parameter> methodReferenceSharedVariableList = new ArrayList<>();
 
@@ -266,7 +315,7 @@ public class StaticTypesMethodReferenceExpressionWriter extends MethodReferenceE
     private MethodNode findMethodRefMethod(final String methodName, final Parameter[] samParameters, final Expression typeOrTargetRef, final ClassNode typeOrTargetRefType) {
         List<MethodNode> methods = findVisibleMethods(methodName, typeOrTargetRefType);
 
-        return chooseMethodRefMethodCandidate(typeOrTargetRef, methods.stream().filter(method -> {
+        methods.removeIf(method -> {
             Parameter[] parameters = method.getParameters();
             if (isTypeReferringInstanceMethod(typeOrTargetRef, method)) {
                 // there is an implicit parameter for "String::length"
@@ -279,8 +328,31 @@ public class StaticTypesMethodReferenceExpressionWriter extends MethodReferenceE
 
                 parameters = plusOne;
             }
-            return parametersCompatible(samParameters, parameters);
-        }).collect(Collectors.toList()));
+
+            // check direct match
+            if (parametersCompatible(samParameters, parameters)) return false;
+
+            // check vararg match
+            if (isVargs(parameters)) {
+                int nParameters = parameters.length;
+                if (samParameters.length == nParameters - 1) { // 0 case
+                    parameters = Arrays.copyOf(parameters, nParameters - 1);
+                    if (parametersCompatible(samParameters, parameters)) return false;
+                }
+                else if (samParameters.length >= nParameters) { // 1+ case
+                    Parameter p = new Parameter(parameters[nParameters - 1].getType().getComponentType(), "");
+                    parameters = Arrays.copyOf(parameters, samParameters.length);
+                    for (int i = nParameters - 1; i < parameters.length; i += 1){
+                        parameters[i] = p;
+                    }
+                    if (parametersCompatible(samParameters, parameters)) return false;
+                }
+            }
+
+            return true; // no match; remove method
+        });
+
+        return chooseMethodRefMethodCandidate(typeOrTargetRef, methods);
     }
 
     private List<MethodNode> findVisibleMethods(final String name, final ClassNode type) {
@@ -310,15 +382,21 @@ public class StaticTypesMethodReferenceExpressionWriter extends MethodReferenceE
                 || (isExtensionMethod(mn) && !((ExtensionMethodNode) mn).isStaticExtension()));
     }
 
+    private static Expression makeClassTarget(final ClassNode target, final Expression source) {
+        Expression expression = classX(target);
+        expression.setSourcePosition(source);
+        return expression;
+    }
+
     private static Parameter[] removeFirstParameter(final Parameter[] parameters) {
         return Arrays.copyOfRange(parameters, 1, parameters.length);
     }
 
     /**
-     * Choose the best method node for method reference.
+     * Chooses the best method node for method reference.
      */
     private static MethodNode chooseMethodRefMethodCandidate(final Expression methodRef, final List<MethodNode> candidates) {
-        if (1 == candidates.size()) return candidates.get(0);
+        if (candidates.size() == 1) return candidates.get(0);
 
         return candidates.stream()
                 .map(e -> Tuple.tuple(e, matchingScore(e, methodRef)))
diff --git a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
index 819da3e79d..649d6f988c 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
@@ -491,9 +491,9 @@ public abstract class StaticTypeCheckingSupport {
         return (type.isDerivedFrom(CLOSURE_TYPE) && isSAMType(toBeAssignedTo));
     }
 
+    @Deprecated
     static boolean isVargs(final Parameter[] parameters) {
-        if (parameters == null || parameters.length == 0) return false;
-        return (parameters[parameters.length - 1].getType().isArray());
+        return ParameterUtils.isVargs(parameters);
     }
 
     public static boolean isCompareToBoolean(final int op) {
diff --git a/src/test/groovy/transform/stc/MethodReferenceTest.groovy b/src/test/groovy/transform/stc/MethodReferenceTest.groovy
index a3f401a1f4..f1188942e7 100644
--- a/src/test/groovy/transform/stc/MethodReferenceTest.groovy
+++ b/src/test/groovy/transform/stc/MethodReferenceTest.groovy
@@ -126,8 +126,41 @@ final class MethodReferenceTest {
         '''
     }
 
-    @Test // class::instanceMethod -- GROOVY-9853
+    @Test // class::instanceMethod -- GROOVY-9813
     void testFunctionCI6() {
+        String head = '''
+            @CompileStatic
+            class C {
+                def <T> List<T> asList(T... a) {
+                    return Arrays.asList(a)
+                }
+                static main(args) {
+        '''
+        String tail = '''
+                }
+            }
+        '''
+
+        shouldFail shell, head + '''
+            Supplier<List> zero = C::asList
+        ''' + tail
+
+        assertScript shell, head + '''
+            Function<C, List> one = C::asList
+            def list = one.apply(new C())
+            assert list.isEmpty()
+        ''' + tail
+
+        assertScript shell, head + '''
+            BiFunction<C, Integer, List> two = C::asList
+            def list = two.apply(new C(),1)
+            assert list.size() == 1
+            assert list[0] == 1
+        ''' + tail
+    }
+
+    @Test // class::instanceMethod -- GROOVY-9853
+    void testFunctionCI7() {
         assertScript shell, '''
             @CompileStatic
             void test() {
@@ -493,6 +526,32 @@ final class MethodReferenceTest {
         '''
     }
 
+    @Test // class::new
+    void testFunctionCN5() {
+        assertScript shell, '''
+            @CompileStatic
+            void p() {
+                Function<String, Integer> f = Integer::new
+                assert [1, 2, 3] == ["1", "2", "3"].stream().map(f).collect(Collectors.toList())
+            }
+
+            p()
+        '''
+    }
+
+    @Test // arrayClass::new
+    void testIntFunctionCN6() {
+        assertScript shell, '''
+            @CompileStatic
+            void p() {
+                IntFunction<Integer[]> f = Integer[]::new
+                assert new Integer[] { 1, 2, 3 } == [1, 2, 3].stream().toArray(f)
+            }
+
+            p()
+        '''
+    }
+
     @Test // class::staticMethod
     void testFunctionCS() {
         assertScript shell, '''
@@ -545,7 +604,7 @@ final class MethodReferenceTest {
     }
 
     @Test // class::staticMethod
-    void testFunctionCS_RHS() {
+    void testFunctionCS4() {
         assertScript shell, '''
             @CompileStatic
             void p() {
@@ -553,13 +612,12 @@ final class MethodReferenceTest {
                 def result = [1, -2, 3].stream().map(f).collect(Collectors.toList())
                 assert [1, 2, 3] == result
             }
-
             p()
         '''
     }
 
     @Test // class::staticMethod
-    void testFunctionCS_RHS_NOTYPE() {
+    void testFunctionCS5() {
         assertScript shell, '''
             @CompileStatic
             void p() {
@@ -567,33 +625,42 @@ final class MethodReferenceTest {
                 def result = [1, -2, 3].stream().map(f).collect(Collectors.toList())
                 assert [1, 2, 3] == result
             }
-
             p()
         '''
     }
 
-    @Test // class::new
-    void testFunctionCN_RHS() {
+    @Test // class::staticMethod -- GROOVY-9813
+    void testFunctionCS6() {
         assertScript shell, '''
             @CompileStatic
             void p() {
-                Function<String, Integer> f = Integer::new
-                assert [1, 2, 3] == ["1", "2", "3"].stream().map(f).collect(Collectors.toList())
+                Supplier<List> zero = Arrays::asList
+                def list = zero.get()
+                assert list.isEmpty()
             }
-
             p()
         '''
-    }
 
-    @Test // arrayClass::new
-    void testIntFunctionCN_RHS() {
         assertScript shell, '''
             @CompileStatic
             void p() {
-                IntFunction<Integer[]> f = Integer[]::new
-                assert new Integer[] { 1, 2, 3 } == [1, 2, 3].stream().toArray(f)
+                Function<Integer, List> one = Arrays::asList
+                def list = one.apply(1)
+                assert list.size() == 1
+                assert list[0] == 1
             }
+            p()
+        '''
 
+        assertScript shell, '''
+            @CompileStatic
+            void p() {
+                BiFunction<Integer, Integer, List> two = Arrays::asList
+                def list = two.apply(2,3)
+                assert list.size() == 2
+                assert list[0] == 2
+                assert list[1] == 3
+            }
             p()
         '''
     }
@@ -606,7 +673,6 @@ final class MethodReferenceTest {
                 def result = ['a', 'ab', 'abc'].stream().map(String::size).collect(Collectors.toList())
                 assert [1, 2, 3] == result
             }
-
             p()
         '''
     }
@@ -619,7 +685,6 @@ final class MethodReferenceTest {
                 def result = [{}, {}, {}].stream().map(Thread::startDaemon).collect(Collectors.toList())
                 assert result.every(e -> e instanceof Thread)
             }
-
             p()
         '''
     }
@@ -633,7 +698,6 @@ final class MethodReferenceTest {
                 assert 3 == result.size()
                 assert ['[a:1]', '[b:2]', '[c:3]'] == result
             }
-
             p()
         '''
     }
@@ -649,7 +713,6 @@ final class MethodReferenceTest {
                 result = [{}, {}, {}].stream().map(Thread::startDaemon).collect(Collectors.toList())
                 assert result.every(e -> e instanceof Thread)
             }
-
             p()
         '''
     }
@@ -713,8 +776,8 @@ final class MethodReferenceTest {
     @Test // GROOVY-10635
     void testRecordComponentMethodReference() {
         assertScript shell, '''
-            record Bar(String name) { }
-
+            record Bar(String name) {
+            }
             def bars = [new Bar(name: 'A'), new Bar(name: 'B')]
             assert bars.stream().map(Bar::name).map(String::toLowerCase).toList() == ['a', 'b']
         '''