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 2024/02/24 19:27:42 UTC

(groovy) branch master updated: GROOVY-11304: SC: scrub lambda generics

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 b1032d28d0 GROOVY-11304: SC: scrub lambda generics
b1032d28d0 is described below

commit b1032d28d0c2dbdcc9a504a21d0c41b088533098
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Sat Feb 24 13:27:40 2024 -0600

    GROOVY-11304: SC: scrub lambda generics
---
 .../classgen/asm/sc/StaticTypesLambdaWriter.java   | 39 +++++++++-------------
 src/test/groovy/bugs/Groovy9770.groovy             | 38 ---------------------
 src/test/groovy/transform/stc/LambdaTest.groovy    | 29 ++++++++++++++++
 3 files changed, 45 insertions(+), 61 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesLambdaWriter.java b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesLambdaWriter.java
index 843c834f16..142312ef6b 100644
--- a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesLambdaWriter.java
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesLambdaWriter.java
@@ -62,7 +62,7 @@ import static org.codehaus.groovy.ast.tools.GeneralUtils.classX;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.declS;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.localVarX;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.returnS;
-import static org.codehaus.groovy.transform.stc.StaticTypesMarker.INFERRED_TYPE;
+import static org.codehaus.groovy.transform.stc.StaticTypesMarker.CLOSURE_ARGUMENTS;
 import static org.codehaus.groovy.transform.stc.StaticTypesMarker.PARAMETER_TYPE;
 import static org.objectweb.asm.Opcodes.ACC_FINAL;
 import static org.objectweb.asm.Opcodes.ACC_PRIVATE;
@@ -108,13 +108,10 @@ public class StaticTypesLambdaWriter extends LambdaWriter implements AbstractFun
             expression.setSerializable(true);
         }
 
-        ClassNode enclosingClass = controller.getClassNode();
-        int modifiers = ACC_FINAL | ACC_PUBLIC;
-        if (enclosingClass.isInterface()) modifiers |= ACC_STATIC;
-        ClassNode lambdaClass = getOrAddLambdaClass(expression, modifiers, abstractMethod);
+        ClassNode lambdaClass = getOrAddLambdaClass(expression, abstractMethod);
         MethodNode lambdaMethod = lambdaClass.getMethods("doCall").get(0);
 
-        boolean canDeserialize = enclosingClass.hasMethod(createDeserializeLambdaMethodName(lambdaClass), createDeserializeLambdaMethodParams());
+        boolean canDeserialize = controller.getClassNode().hasMethod(createDeserializeLambdaMethodName(lambdaClass), createDeserializeLambdaMethodParams());
         if (!canDeserialize) {
             if (expression.isSerializable()) {
                 addDeserializeLambdaMethodForEachLambdaExpression(expression, lambdaClass);
@@ -127,7 +124,7 @@ public class StaticTypesLambdaWriter extends LambdaWriter implements AbstractFun
         mv.visitInvokeDynamicInsn(
                 abstractMethod.getName(),
                 createAbstractMethodDesc(functionalType.redirect(), lambdaClass),
-                createBootstrapMethod(enclosingClass.isInterface(), expression.isSerializable()),
+                createBootstrapMethod(controller.getClassNode().isInterface(), expression.isSerializable()),
                 createBootstrapMethodArguments(createMethodDescriptor(abstractMethod), H_INVOKEVIRTUAL, lambdaClass, lambdaMethod, lambdaMethod.getParameters(), expression.isSerializable())
         );
         if (expression.isSerializable()) {
@@ -206,9 +203,9 @@ public class StaticTypesLambdaWriter extends LambdaWriter implements AbstractFun
         return BytecodeHelper.getMethodDescriptor(functionalInterface, lambdaSharedVariables.toArray(Parameter.EMPTY_ARRAY));
     }
 
-    private ClassNode getOrAddLambdaClass(final LambdaExpression expression, final int modifiers, final MethodNode abstractMethod) {
+    private ClassNode getOrAddLambdaClass(final LambdaExpression expression, final MethodNode abstractMethod) {
         return lambdaClassNodes.computeIfAbsent(expression, key -> {
-            ClassNode lambdaClass = createLambdaClass(expression, modifiers, abstractMethod);
+            ClassNode lambdaClass = createLambdaClass(expression, ACC_FINAL | ACC_PUBLIC | ACC_STATIC, abstractMethod);
             controller.getAcg().addInnerClass(lambdaClass);
             lambdaClass.addInterface(GENERATED_LAMBDA_TYPE);
             lambdaClass.putNodeMetaData(StaticCompilationMetadataKeys.STATIC_COMPILE_NODE, Boolean.TRUE);
@@ -225,10 +222,8 @@ public class StaticTypesLambdaWriter extends LambdaWriter implements AbstractFun
     protected ClassNode createLambdaClass(final LambdaExpression expression, final int modifiers, final MethodNode abstractMethod) {
         ClassNode enclosingClass = controller.getClassNode();
         ClassNode outermostClass = controller.getOutermostClass();
-        boolean staticMethodOrInStaticClass = (controller.isStaticMethod() || enclosingClass.isStaticClass());
 
         InnerClassNode lambdaClass = new InnerClassNode(enclosingClass, nextLambdaClassName(), modifiers, CLOSURE_TYPE.getPlainNodeReference());
-      //lambdaClass.setUsingGenerics(outermostClass.isUsingGenerics());
         lambdaClass.setEnclosingMethod(controller.getMethodNode());
         lambdaClass.setSourcePosition(expression);
         lambdaClass.setSynthetic(true);
@@ -236,7 +231,8 @@ public class StaticTypesLambdaWriter extends LambdaWriter implements AbstractFun
         if (controller.isInScriptBody()) {
             lambdaClass.setScriptBody(true);
         }
-        if (staticMethodOrInStaticClass) {
+        if (controller.isStaticMethod()
+                || enclosingClass.isStaticClass()) {
             lambdaClass.setStaticClass(true);
         }
         if (expression.isSerializable()) {
@@ -244,9 +240,10 @@ public class StaticTypesLambdaWriter extends LambdaWriter implements AbstractFun
         }
 
         MethodNode syntheticLambdaMethodNode = addSyntheticLambdaMethodNode(expression, lambdaClass, abstractMethod);
-        Parameter[] localVariableParameters = expression.getNodeMetaData(LAMBDA_SHARED_VARIABLES);
 
+        Parameter[] localVariableParameters = expression.getNodeMetaData(LAMBDA_SHARED_VARIABLES);
         addFieldsAndGettersForLocalVariables(lambdaClass, localVariableParameters);
+
         ConstructorNode constructorNode = addConstructor(expression, localVariableParameters, lambdaClass, createBlockStatementForConstructor(expression, outermostClass, enclosingClass));
         constructorNode.putNodeMetaData(IS_GENERATED_CONSTRUCTOR, Boolean.TRUE);
 
@@ -282,17 +279,13 @@ public class StaticTypesLambdaWriter extends LambdaWriter implements AbstractFun
 
     private Parameter[] createParametersWithExactType(final LambdaExpression expression, final MethodNode abstractMethod) {
         Parameter[] targetParameters = abstractMethod.getParameters();
-        Parameter[] parameters = getParametersSafe(expression);
-        for (int i = 0, n = parameters.length; i < n; i += 1) {
-            Parameter targetParameter = targetParameters[i];
-            Parameter parameter = parameters[i];
-            ClassNode inferredType = parameter.getNodeMetaData(INFERRED_TYPE);
-            if (inferredType != null) {
-                ClassNode type = convertParameterType(targetParameter.getType(), parameter.getType(), inferredType);
-                parameter.setType(type);
-            }
+        Parameter[] lambdaParameters = getParametersSafe(expression);
+        ClassNode[] lambdaParamTypes = expression.getNodeMetaData(CLOSURE_ARGUMENTS);
+        for (int i = 0, n = lambdaParameters.length; i < n; i += 1) {
+            ClassNode resolvedType = convertParameterType(targetParameters[i].getType(), lambdaParameters[i].getType(), lambdaParamTypes[i]);
+            lambdaParameters[i].setType(resolvedType);
         }
-        return parameters;
+        return lambdaParameters;
     }
 
     private void addDeserializeLambdaMethod() {
diff --git a/src/test/groovy/bugs/Groovy9770.groovy b/src/test/groovy/bugs/Groovy9770.groovy
deleted file mode 100644
index 557c93fb6c..0000000000
--- a/src/test/groovy/bugs/Groovy9770.groovy
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- *  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 groovy.test.GroovyTestCase
-
-class Groovy9770 extends GroovyTestCase {
-    void testLambdaClassModifiers() {
-        assertScript '''
-            @groovy.transform.CompileStatic
-            class Foo {
-                def bar(String arg) {
-                    java.util.function.Function<String, String> up = (String s) -> { s.toUpperCase() }
-                    up(arg)
-                }
-            }
-
-            assert new Foo().bar('hello') == 'HELLO'
-            assert getClass().classLoader.loadClass('Foo$_bar_lambda1').modifiers == 17 // PUBLIC | FINAL
-        '''
-    }
-}
diff --git a/src/test/groovy/transform/stc/LambdaTest.groovy b/src/test/groovy/transform/stc/LambdaTest.groovy
index fb06d6203f..a75a3f57a8 100644
--- a/src/test/groovy/transform/stc/LambdaTest.groovy
+++ b/src/test/groovy/transform/stc/LambdaTest.groovy
@@ -258,6 +258,19 @@ final class LambdaTest {
         }
     }
 
+    // GROOVY-11304
+    @Test
+    void testCollectors3() {
+        assertScript shell, '''
+            List<String> list = ['a', 'b', 'c']
+            Map<String, Integer> map = list.stream().collect(
+                Collectors.toMap(Function.identity(), (k) -> 1, (v, w) -> v + w)
+            )
+
+            assert map == [a: 1, b: 1, c: 1]
+        '''
+    }
+
     @Test
     void testFunctionWithLocalVariables() {
         assertScript shell, '''
@@ -1765,4 +1778,20 @@ final class LambdaTest {
             }
         '''
     }
+
+    // GROOVY-9770
+    @Test
+    void testLambdaClassIsntSynthetic() {
+        assertScript shell, '''
+            class Foo {
+                def bar(String arg) {
+                    Function<String, String> fun = (String s) -> s.toUpperCase()
+                    fun.apply(arg)
+                }
+            }
+
+            assert new Foo().bar('hello') == 'HELLO'
+            assert this.class.classLoader.loadClass('Foo$_bar_lambda1').modifiers == 25 // public(1) + static(8) + final(16)
+        '''
+    }
 }