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 7a7e7b2ef8 GROOVY-11479: STC: closure or lambda parameter type must 
remain mutable
7a7e7b2ef8 is described below

commit 7a7e7b2ef8a40b7cf648017f57c1ea0ddd8ba87f
Author: Eric Milles <[email protected]>
AuthorDate: Wed Sep 25 10:51:50 2024 -0500

    GROOVY-11479: STC: closure or lambda parameter type must remain mutable
    
    do not use the type from the SAM directory
---
 .../asm/sc/AbstractFunctionalInterfaceWriter.java  | 25 +++++++++++----
 .../transform/stc/StaticTypeCheckingVisitor.java   |  5 ++-
 .../groovy/classgen/asm/TypeAnnotationsTest.groovy | 36 ++++++++++++++++++++++
 3 files changed, 59 insertions(+), 7 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 4292491afa..ceb280c43b 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
@@ -33,6 +33,7 @@ import static 
org.codehaus.groovy.ast.ClassHelper.getUnwrapper;
 import static org.codehaus.groovy.ast.ClassHelper.getWrapper;
 import static org.codehaus.groovy.ast.ClassHelper.isDynamicTyped;
 import static org.codehaus.groovy.ast.ClassHelper.isPrimitiveType;
+import static 
org.codehaus.groovy.ast.tools.GenericsUtils.hasUnresolvedGenerics;
 import static 
org.codehaus.groovy.classgen.asm.BytecodeHelper.getClassInternalName;
 import static 
org.codehaus.groovy.classgen.asm.BytecodeHelper.getMethodDescriptor;
 
@@ -113,12 +114,14 @@ public interface AbstractFunctionalInterfaceWriter {
             throw new RuntimeParserException("The inferred type[" + 
inferredType.redirect() + "] is not compatible with the parameter type[" + 
parameterType.redirect() + "]", parameterType);
         }
 
-        ClassNode type = inferredType;
+        ClassNode type;
         if (isPrimitiveType(parameterType)) {
             if (!isPrimitiveType(inferredType)) {
                 // The non-primitive type and primitive type are not allowed 
to mix since Java 9+
                 // java.lang.invoke.LambdaConversionException: Type mismatch 
for instantiated parameter 0: class java.lang.Integer is not a subtype of int
-                type = getUnwrapper(inferredType);
+                type = getUnwrapper(inferredType).getPlainNodeReference(false);
+            } else {
+                type = inferredType.getPlainNodeReference(false);
             }
         } else if (isPrimitiveType(inferredType)) {
             // GROOVY-9790: bootstrap method initialization exception raised 
when lambda parameter type is wrong
@@ -128,11 +131,21 @@ public interface AbstractFunctionalInterfaceWriter {
                     && (parameterType.equals(getUnwrapper(parameterType)) || 
inferredType.equals(getWrapper(inferredType)))) { // (2)
                 // The non-primitive type and primitive type are not allowed 
to mix since Java 9+
                 // java.lang.invoke.LambdaConversionException: Type mismatch 
for instantiated parameter 0: int is not a subtype of class java.lang.Object
-                type = getWrapper(inferredType);
+                type = getWrapper(inferredType).getPlainNodeReference();
+            } else {
+                type = inferredType.getPlainNodeReference(false);
+            }
+        } else {
+            type = inferredType;
+            // GROOVY-11304: no placeholders
+            if (hasUnresolvedGenerics(type)) type = type.redirect();
+            // GROOVY-11479: mutable for node metadata or type annotations
+            if (type.toString(false).equals(parameterType.toString(false))) {
+                type = parameterType;
+            } else {
+                // TODO: deep copy if type args set
+                type = type.getPlainNodeReference();
             }
-        }
-        if (type.isGenericsPlaceHolder()) {
-            type = type.redirect();
         }
         return type;
     }
diff --git 
a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
 
b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
index db5446a4e5..1fbaef6a7a 100644
--- 
a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ 
b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -1035,7 +1035,10 @@ out:    if ((samParameterTypes.length == 1 && 
isOrImplements(samParameterTypes[0
             for (int i = 0; i < n; i += 1) {
                 Parameter parameter = closureParameters[i];
                 if (parameter.isDynamicTyped()) {
-                    parameter.setType(expectedTypes[i]); // GROOVY-11083, 
GROOVY-11085, et al.
+                    ClassNode type = 
expectedTypes[i].getPlainNodeReference(false); // GROOVY-11479
+                    if (!expectedTypes[i].isGenericsPlaceHolder())
+                        
type.setGenericsTypes(expectedTypes[i].getGenericsTypes());
+                    parameter.setType(type); // GROOVY-11083, GROOVY-11085, et 
al.
                 } else {
                     checkParamType(parameter, expectedTypes[i], i == n-1, 
rhsExpression instanceof LambdaExpression);
                 }
diff --git 
a/src/test/org/codehaus/groovy/classgen/asm/TypeAnnotationsTest.groovy 
b/src/test/org/codehaus/groovy/classgen/asm/TypeAnnotationsTest.groovy
index 74746e3eae..d8758d9de3 100644
--- a/src/test/org/codehaus/groovy/classgen/asm/TypeAnnotationsTest.groovy
+++ b/src/test/org/codehaus/groovy/classgen/asm/TypeAnnotationsTest.groovy
@@ -257,6 +257,42 @@ final class TypeAnnotationsTest extends 
AbstractBytecodeTestCase {
         ])
     }
 
+    // GROOVY-11479
+    void testTypeAnnotationsForClosure() {
+        def bytecode = compile(classNamePattern: 'Foo\\$_closure1', method: 
'doCall', imports + '''
+            @Retention(RUNTIME) @Target(TYPE_USE) @interface TypeAnno0 { }
+            @Retention(RUNTIME) @Target(TYPE_USE) @interface TypeAnno1 { }
+
+            @groovy.transform.CompileStatic
+            class Foo {
+                @TypeAnno0 java.util.function.IntUnaryOperator bar = { 
@TypeAnno1 def i -> 1 }
+            }
+        ''')
+        assert bytecode.hasStrictSequence([
+                'public doCall(I)Ljava/lang/Integer;',
+                '@LTypeAnno1;() : METHOD_FORMAL_PARAMETER 0, null',
+                'L0'
+        ])
+    }
+
+    // GROOVY-11479
+    void testTypeAnnotationsForLambda() {
+        def bytecode = compile(classNamePattern: 'Foo\\$_lambda1', method: 
'doCall', imports + '''
+            @Retention(RUNTIME) @Target(TYPE_USE) @interface TypeAnno0 { }
+            @Retention(RUNTIME) @Target(TYPE_USE) @interface TypeAnno1 { }
+
+            @groovy.transform.CompileStatic
+            class Foo {
+                @TypeAnno0 java.util.function.IntUnaryOperator bar = 
(@TypeAnno1 int i) -> 1
+            }
+        ''')
+        assert bytecode.hasStrictSequence([
+                'public doCall(I)I',
+                '@LTypeAnno1;() : METHOD_FORMAL_PARAMETER 0, null',
+                'L0'
+        ])
+    }
+
     void testTypeAnnotationsForField1() {
         def bytecode = compile(classNamePattern: 'Foo', field: 'foo', imports 
+ '''
             @Retention(RUNTIME) @Target(FIELD) @interface FieldAnno { String 
value() }

Reply via email to