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/07/22 16:21:43 UTC

[groovy] 02/02: GROOVY-10701: null-safe `findSAM`, `isSAMType` and `isClosureWithType`

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

commit 78276ce051e50193c5a18d80c44febaf17ab17fd
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Fri Jul 22 11:11:43 2022 -0500

    GROOVY-10701: null-safe `findSAM`, `isSAMType` and `isClosureWithType`
---
 src/main/java/org/codehaus/groovy/ast/ClassHelper.java |  1 +
 .../transform/stc/StaticTypeCheckingVisitor.java       |  7 ++++++-
 .../groovy/transform/stc/TernaryOperatorSTCTest.groovy | 18 ++++++++++++++++++
 3 files changed, 25 insertions(+), 1 deletion(-)

diff --git a/src/main/java/org/codehaus/groovy/ast/ClassHelper.java b/src/main/java/org/codehaus/groovy/ast/ClassHelper.java
index e190ffcfb3..d4daf9face 100644
--- a/src/main/java/org/codehaus/groovy/ast/ClassHelper.java
+++ b/src/main/java/org/codehaus/groovy/ast/ClassHelper.java
@@ -560,6 +560,7 @@ public class ClassHelper {
      * @return the method node if type is a SAM type, null otherwise
      */
     public static MethodNode findSAM(final ClassNode type) {
+        if (type == null) return null;
         if (type.isInterface()) {
             MethodNode sam = null;
             for (MethodNode mn : type.getAbstractMethods()) {
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 0b26ae18c9..11e12da0ff 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -1072,7 +1072,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
     }
 
     private static boolean isClosureWithType(final ClassNode type) {
-        return type.equals(CLOSURE_TYPE) && Optional.ofNullable(type.getGenericsTypes()).filter(gts -> gts != null && gts.length == 1).isPresent();
+        return CLOSURE_TYPE.equals(type) && Optional.ofNullable(type.getGenericsTypes()).filter(gts -> gts != null && gts.length == 1).isPresent();
     }
 
     private static boolean isCompoundAssignment(final Expression exp) {
@@ -4265,11 +4265,16 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
     private ClassNode checkForTargetType(final Expression expr, final ClassNode type) {
         ClassNode targetType = null;
         MethodNode enclosingMethod = typeCheckingContext.getEnclosingMethod();
+        MethodCall enclosingMethodCall = (MethodCall)typeCheckingContext.getEnclosingMethodCall();
         BinaryExpression enclosingExpression = typeCheckingContext.getEnclosingBinaryExpression();
         if (enclosingExpression != null
                 && isAssignment(enclosingExpression.getOperation().getType())
                 && isTypeSource(expr, enclosingExpression.getRightExpression())) {
             targetType = getDeclaredOrInferredType(enclosingExpression.getLeftExpression());
+        } else if (enclosingMethodCall != null
+                && InvocationWriter.makeArgumentList(enclosingMethodCall.getArguments())
+                        .getExpressions().stream().anyMatch(arg -> isTypeSource(expr, arg))) {
+            // TODO: locate method target parameter
         } else if (enclosingMethod != null
                 && !enclosingMethod.isAbstract()
                 && !enclosingMethod.isVoidMethod()
diff --git a/src/test/groovy/transform/stc/TernaryOperatorSTCTest.groovy b/src/test/groovy/transform/stc/TernaryOperatorSTCTest.groovy
index 92b708e40c..40dd80722e 100644
--- a/src/test/groovy/transform/stc/TernaryOperatorSTCTest.groovy
+++ b/src/test/groovy/transform/stc/TernaryOperatorSTCTest.groovy
@@ -197,6 +197,24 @@ class TernaryOperatorSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
+    // GROOVY-10701
+    void testFunctionalInterfaceTarget3() {
+        for (type in ['Function<T,T>', 'UnaryOperator<T>']) {
+            assertScript """import java.util.function.*
+
+                def <T> T m1($type x) {
+                    x.apply(null)
+                }
+                double m2(double d) {
+                    Math.PI
+                }
+
+                def result = m1(true ? (Double d) -> 42.0d : this::m2)
+                assert result == 42.0d
+            """
+        }
+    }
+
     // GROOVY-10357
     void testAbstractMethodDefault() {
         assertScript '''