You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by su...@apache.org on 2021/03/24 14:43:34 UTC

[groovy] branch master updated (8eaae55 -> 9a63e8c)

This is an automated email from the ASF dual-hosted git repository.

sunlan pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/groovy.git.


    from 8eaae55  GROOVY-8104: fix this$0 for closure with anon. inner class of inner type
     new 39422ed  GROOVY-9995: infer ctor call diamond type from closure target type
     new 9a63e8c  GROOVY-9997: infer closure/lambda params + return types from cast/coerce

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../transform/stc/StaticTypeCheckingVisitor.java   | 46 +++++++++++++++-------
 .../groovy/transform/stc/GenericsSTCTest.groovy    | 20 ++++++++++
 src/test/groovy/transform/stc/LambdaTest.groovy    | 15 +++++++
 .../groovy/console/ui/ButtonOrTextEditor.groovy    |  4 +-
 4 files changed, 69 insertions(+), 16 deletions(-)

[groovy] 02/02: GROOVY-9997: infer closure/lambda params + return types from cast/coerce

Posted by su...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

sunlan pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/groovy.git

commit 9a63e8cc7bd9bdb1efd97046907549199260e715
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Mon Mar 22 21:54:30 2021 -0500

    GROOVY-9997: infer closure/lambda params + return types from cast/coerce
---
 .../transform/stc/StaticTypeCheckingVisitor.java    | 21 ++++++++++++---------
 src/test/groovy/transform/stc/LambdaTest.groovy     | 15 +++++++++++++++
 .../groovy/console/ui/ButtonOrTextEditor.groovy     |  4 ++--
 3 files changed, 29 insertions(+), 11 deletions(-)

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 e611cee..888a1c5 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -4092,16 +4092,19 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
 
     @Override
     public void visitCastExpression(final CastExpression expression) {
-        super.visitCastExpression(expression);
-        if (!expression.isCoerce()) {
-            ClassNode targetType = expression.getType();
-            Expression source = expression.getExpression();
-            ClassNode expressionType = getType(source);
-            if (!checkCast(targetType, source) && !isDelegateOrOwnerInClosure(source)) {
-                addStaticTypeError("Inconvertible types: cannot cast " + prettyPrintType(expressionType) + " to " + prettyPrintType(targetType), expression);
-            }
+        ClassNode type = expression.getType();
+        Expression source = expression.getExpression();
+        if (isFunctionalInterface(type)) { // GROOVY-9997
+            processFunctionalInterfaceAssignment(type, source);
+        } else if (isClosureWithType(type) && source instanceof ClosureExpression) {
+            storeInferredReturnType(source, getCombinedBoundType(type.getGenericsTypes()[0]));
+        }
+
+        source.visit(this);
+
+        if (!expression.isCoerce() && !checkCast(type, source) && !isDelegateOrOwnerInClosure(source)) {
+            addStaticTypeError("Inconvertible types: cannot cast " + prettyPrintType(getType(source)) + " to " + prettyPrintType(type), expression);
         }
-        storeType(expression, expression.getType());
     }
 
     private boolean isDelegateOrOwnerInClosure(final Expression exp) {
diff --git a/src/test/groovy/transform/stc/LambdaTest.groovy b/src/test/groovy/transform/stc/LambdaTest.groovy
index 618f18f..be0e437 100644
--- a/src/test/groovy/transform/stc/LambdaTest.groovy
+++ b/src/test/groovy/transform/stc/LambdaTest.groovy
@@ -330,6 +330,21 @@ final class LambdaTest {
         '''
     }
 
+    @Test // GROOVY-9997
+    void testComparator3() {
+        assertScript '''
+            @groovy.transform.TypeChecked
+            void test() {
+                def cast = (Comparator<Integer>) (a, b) -> Integer.compare(a, b)
+                assert cast.compare(0,0) == 0
+
+                def coerce = ((a, b) -> Integer.compare(a, b)) as Comparator<Integer>
+                assert coerce.compare(0,0) == 0
+            }
+            test()
+        '''
+    }
+
     @Test
     void testFunctionWithLocalVariables() {
         assertScript '''
diff --git a/subprojects/groovy-console/src/main/groovy/groovy/console/ui/ButtonOrTextEditor.groovy b/subprojects/groovy-console/src/main/groovy/groovy/console/ui/ButtonOrTextEditor.groovy
index ddb97ce..38992ce 100644
--- a/subprojects/groovy-console/src/main/groovy/groovy/console/ui/ButtonOrTextEditor.groovy
+++ b/subprojects/groovy-console/src/main/groovy/groovy/console/ui/ButtonOrTextEditor.groovy
@@ -44,12 +44,12 @@ class ButtonOrTextEditor extends AbstractCellEditor implements TableCellEditor {
     Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
         if (value instanceof JButton) {
             editorComponent = value
-            ((JButton) editorComponent).addActionListener({ fireEditingStopped() } as ActionListener)
+            ((JButton) editorComponent).addActionListener({ e -> fireEditingStopped() } as ActionListener)
         } else if (value instanceof JTextArea) {
             editorComponent = value
         } else if (value) {
             editorComponent = new JTextArea(value.toString())
-            editorComponent.addFocusListener({ fireEditingCanceled() } as FocusListener)
+            editorComponent.addFocusListener({ e -> fireEditingCanceled() } as FocusListener)
         } else {
             editorComponent = null
         }

[groovy] 01/02: GROOVY-9995: infer ctor call diamond type from closure target type

Posted by su...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

sunlan pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/groovy.git

commit 39422ed19bb739603d56ec5aa7e07bd2f89cc649
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Mon Mar 22 12:27:23 2021 -0500

    GROOVY-9995: infer ctor call diamond type from closure target type
---
 .../transform/stc/StaticTypeCheckingVisitor.java   | 25 +++++++++++++++++-----
 .../groovy/transform/stc/GenericsSTCTest.groovy    | 20 +++++++++++++++++
 2 files changed, 40 insertions(+), 5 deletions(-)

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 ed54498..e611cee 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -749,8 +749,12 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
                 lType = getType(leftExpression);
             } else {
                 lType = getType(leftExpression);
-                if (op == ASSIGN && isFunctionalInterface(lType)) {
-                    processFunctionalInterfaceAssignment(lType, rightExpression);
+                if (op == ASSIGN) {
+                    if (isFunctionalInterface(lType)) {
+                        processFunctionalInterfaceAssignment(lType, rightExpression);
+                    } else if (isClosureWithType(lType) && rightExpression instanceof ClosureExpression) {
+                        storeInferredReturnType(rightExpression, getCombinedBoundType(lType.getGenericsTypes()[0]));
+                    }
                 }
                 rightExpression.visit(this);
             }
@@ -994,6 +998,10 @@ 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();
+    }
+
     private boolean isCompoundAssignment(final Expression exp) {
         if (!(exp instanceof BinaryExpression)) return false;
         int type = ((BinaryExpression) exp).getOperation().getType();
@@ -1275,7 +1283,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
 
         ClassNode rTypeInferred, rTypeWrapped; // check for instanceof and spreading
         if (rightExpression instanceof VariableExpression && hasInferredReturnType(rightExpression) && assignmentExpression.getOperation().getType() == ASSIGN) {
-            rTypeInferred = rightExpression.getNodeMetaData(INFERRED_RETURN_TYPE);
+            rTypeInferred = getInferredReturnType(rightExpression);
         } else {
             rTypeInferred = rightExpressionType;
         }
@@ -1847,6 +1855,8 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
                 ClassNode lType = getType(node);
                 if (isFunctionalInterface(lType)) { // GROOVY-9977
                     processFunctionalInterfaceAssignment(lType, init);
+                } else if (isClosureWithType(lType) && init instanceof ClosureExpression) {
+                    storeInferredReturnType(init, getCombinedBoundType(lType.getGenericsTypes()[0]));
                 }
                 init.visit(this);
                 ClassNode rType = getType(init);
@@ -2147,11 +2157,16 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         Expression expression = statement.getExpression();
         ClassNode type;
         if (expression instanceof VariableExpression && hasInferredReturnType(expression)) {
-            type = expression.getNodeMetaData(INFERRED_RETURN_TYPE);
+            type = getInferredReturnType(expression);
         } else {
             type = getType(expression);
         }
         if (typeCheckingContext.getEnclosingClosure() != null) {
+            // GROOVY-9995: return ctor call with diamond operator
+            if (expression instanceof ConstructorCallExpression) {
+                ClassNode inferredClosureReturnType = getInferredReturnType(typeCheckingContext.getEnclosingClosure().getClosureExpression());
+                if (inferredClosureReturnType != null) inferDiamondType((ConstructorCallExpression) expression, inferredClosureReturnType);
+            }
             return type;
         }
         MethodNode enclosingMethod = typeCheckingContext.getEnclosingMethod();
@@ -4159,7 +4174,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
      * @param type the inferred type of {@code expr}
      */
     private ClassNode checkForTargetType(final Expression expr, final ClassNode type) {
-        ClassNode sourceType = (hasInferredReturnType(expr) ? expr.getNodeMetaData(INFERRED_RETURN_TYPE) : type);
+        ClassNode sourceType = (hasInferredReturnType(expr) ? getInferredReturnType(expr) : type);
 
         ClassNode targetType = null;
         MethodNode enclosingMethod = typeCheckingContext.getEnclosingMethod();
diff --git a/src/test/groovy/transform/stc/GenericsSTCTest.groovy b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
index dc1a4ae..7c74674 100644
--- a/src/test/groovy/transform/stc/GenericsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
@@ -475,6 +475,26 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
+    // GROOVY-9995
+    void testDiamondInferrenceFromConstructor12() {
+        [
+            ['Closure<A<Long>>', 'java.util.concurrent.Callable<A<Long>>'],
+            ['new A<>(42L)', 'return new A<>(42L)']
+        ].combinations { functionalType, returnStmt ->
+            assertScript """
+                @groovy.transform.TupleConstructor(defaults=false)
+                class A<T extends Number> {
+                    T p
+                }
+                $functionalType callable = { ->
+                    $returnStmt
+                }
+                Long n = callable.call().p
+                assert n == 42L
+            """
+        }
+    }
+
     void testLinkedListWithListArgument() {
         assertScript '''
             List<String> list = new LinkedList<String>(['1','2','3'])