You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by pa...@apache.org on 2020/09/22 11:53:10 UTC

[groovy] branch master updated (360fbc5 -> 745f567)

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

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


    from 360fbc5  GROOVY-9744: additional refactoring
     new 86953af  GROOVY-9751: STC: add inferencing of method pointer/reference expression
     new d84b89d  GROOVY-9751: STC: extension may fix missing method or ambiguous methods
     new 745f567  GROOVY-9463: STC: add error for unknown method pointer (closes #1373)

The 3 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   | 60 +++++++++++++++++++++-
 src/test/groovy/transform/stc/BugsSTCTest.groovy   |  8 ++-
 .../groovy/transform/stc/GenericsSTCTest.groovy    | 34 ++++++++++++
 3 files changed, 99 insertions(+), 3 deletions(-)


[groovy] 01/03: GROOVY-9751: STC: add inferencing of method pointer/reference expression

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

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

commit 86953afca060c5be300af7eb60fe8e235f1456a5
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Mon Sep 21 14:03:24 2020 -0500

    GROOVY-9751: STC: add inferencing of method pointer/reference expression
---
 .../transform/stc/StaticTypeCheckingVisitor.java   | 49 +++++++++++++++++++++-
 .../groovy/transform/stc/GenericsSTCTest.groovy    | 34 +++++++++++++++
 2 files changed, 81 insertions(+), 2 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 3f93d0e..108fba4 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -69,6 +69,7 @@ import org.codehaus.groovy.ast.expr.MapEntryExpression;
 import org.codehaus.groovy.ast.expr.MapExpression;
 import org.codehaus.groovy.ast.expr.MethodCall;
 import org.codehaus.groovy.ast.expr.MethodCallExpression;
+import org.codehaus.groovy.ast.expr.MethodPointerExpression;
 import org.codehaus.groovy.ast.expr.MethodReferenceExpression;
 import org.codehaus.groovy.ast.expr.NotExpression;
 import org.codehaus.groovy.ast.expr.PostfixExpression;
@@ -240,6 +241,7 @@ import static org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.extrac
 import static org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.extractGenericsParameterMapOfThis;
 import static org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.filterMethodsByVisibility;
 import static org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.findDGMMethodsByNameAndArguments;
+import static org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.findDGMMethodsForClassNode;
 import static org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.findSetters;
 import static org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.findTargetVariable;
 import static org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.fullyResolveType;
@@ -705,7 +707,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
             storeType(expression, ClassHelper.make(IntRange.class));
         } else {
             ClassNode rangeType = RANGE_TYPE.getPlainNodeReference();
-            rangeType.setGenericsTypes(new GenericsType[]{new GenericsType(WideningCategories.lowestUpperBound(fromType, toType))});
+            rangeType.setGenericsTypes(new GenericsType[]{new GenericsType(lowestUpperBound(fromType, toType))});
             storeType(expression, rangeType);
         }
     }
@@ -2368,6 +2370,49 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         }
     }
 
+    @Override
+    public void visitMethodPointerExpression(final MethodPointerExpression expression) {
+        super.visitMethodPointerExpression(expression);
+        Expression nameExpr = expression.getMethodName();
+        if (nameExpr instanceof ConstantExpression
+                && getType(nameExpr).equals(STRING_TYPE)) {
+            String nameText = nameExpr.getText();
+
+            if ("new".equals(nameText)) {
+                ClassNode receiverType = getType(expression.getExpression());
+                if (isClassClassNodeWrappingConcreteType(receiverType)) {
+                    storeType(expression, wrapClosureType(receiverType));
+                }
+                return;
+            }
+
+            List<Receiver<String>> receivers = new ArrayList<>();
+            addReceivers(receivers, makeOwnerList(expression.getExpression()), false);
+
+            List<MethodNode> candidates = EMPTY_METHODNODE_LIST;
+            for (Receiver<String> currentReceiver : receivers) {
+                ClassNode receiverType = wrapTypeIfNecessary(currentReceiver.getType());
+
+                candidates = findMethodsWithGenerated(receiverType, nameText);
+                collectAllInterfaceMethodsByName(receiverType, nameText, candidates);
+                if (isBeingCompiled(receiverType)) candidates.addAll(GROOVY_OBJECT_TYPE.getMethods(nameText));
+                candidates.addAll(findDGMMethodsForClassNode(getTransformLoader(), receiverType, nameText));
+                candidates = filterMethodsByVisibility(candidates, typeCheckingContext.getEnclosingClassNode());
+
+                if (!candidates.isEmpty()) {
+                    break;
+                }
+            }
+
+            if (!candidates.isEmpty()) {
+                candidates.stream().map(MethodNode::getReturnType)
+                        .reduce(WideningCategories::lowestUpperBound)
+                        .filter(returnType -> !returnType.equals(OBJECT_TYPE))
+                        .ifPresent(returnType -> storeType(expression, wrapClosureType(returnType)));
+            }
+        }
+    }
+
     private static ClassNode wrapClosureType(final ClassNode returnType) {
         ClassNode inferredType = CLOSURE_TYPE.getPlainNodeReference();
         inferredType.setGenericsTypes(new GenericsType[]{new GenericsType(wrapTypeIfNecessary(returnType))});
@@ -3066,7 +3111,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         } else {
             ClassNode[] upperBounds = genericsType.getUpperBounds();
             if (upperBounds != null) {
-                value = WideningCategories.lowestUpperBound(Arrays.asList(upperBounds));
+                value = lowestUpperBound(Arrays.asList(upperBounds));
             }
         }
         return value;
diff --git a/src/test/groovy/transform/stc/GenericsSTCTest.groovy b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
index 5f4a65f..6ddc989 100644
--- a/src/test/groovy/transform/stc/GenericsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
@@ -587,6 +587,40 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
+    // GROOVY-9751
+    void testShouldUseMethodGenericType5() {
+        assertScript '''
+            interface Service {
+                Number transform(String s)
+            }
+            void test(Service service) {
+                Set<Number> numbers = []
+                List<String> strings = ['1','2','3']
+                numbers.addAll(strings.collect(service.&transform))
+            }
+            test({ String s -> Integer.valueOf(s) } as Service)
+        '''
+    }
+
+    void testShouldUseMethodGenericType6() {
+        assertScript '''
+            @ASTTest(phase=INSTRUCTION_SELECTION, value={
+                def type = node.rightExpression.getNodeMetaData(INFERRED_TYPE)
+                assert type.equals(CLOSURE_TYPE)
+                assert type.getGenericsTypes()[0].getType().equals(STRING_TYPE)
+            })
+            def ptr = "".&toString
+        '''
+        assertScript '''
+            @ASTTest(phase=INSTRUCTION_SELECTION, value={
+                def type = node.rightExpression.getNodeMetaData(INFERRED_TYPE)
+                assert type.equals(CLOSURE_TYPE)
+                assert type.getGenericsTypes()[0].getType().equals(Double_TYPE)
+            })
+            def ptr = Math.&abs
+        '''
+    }
+
     // GROOVY-5516
     void testAddAllWithCollectionShouldBeAllowed() {
         assertScript '''import org.codehaus.groovy.transform.stc.ExtensionMethodNode


[groovy] 02/03: GROOVY-9751: STC: extension may fix missing method or ambiguous methods

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

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

commit d84b89dbaf83beb2eaf7f7b100ce62034022495a
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Mon Sep 21 14:06:16 2020 -0500

    GROOVY-9751: STC: extension may fix missing method or ambiguous methods
---
 .../codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java   | 7 +++++++
 1 file changed, 7 insertions(+)

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 108fba4..c2be2f1 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -2404,6 +2404,13 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
                 }
             }
 
+            if (candidates.isEmpty()) {
+                candidates = extension.handleMissingMethod(
+                    getType(expression.getExpression()), nameText, null, null, null);
+            } else if (candidates.size() > 1) {
+                candidates = extension.handleAmbiguousMethods(candidates, expression);
+            }
+
             if (!candidates.isEmpty()) {
                 candidates.stream().map(MethodNode::getReturnType)
                         .reduce(WideningCategories::lowestUpperBound)


[groovy] 03/03: GROOVY-9463: STC: add error for unknown method pointer (closes #1373)

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

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

commit 745f567bc1beea5b7cc14e43fe3de1b77f214d6b
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Mon Sep 21 14:11:32 2020 -0500

    GROOVY-9463: STC: add error for unknown method pointer (closes #1373)
---
 .../codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java  | 4 ++++
 src/test/groovy/transform/stc/BugsSTCTest.groovy                  | 8 +++++++-
 2 files changed, 11 insertions(+), 1 deletion(-)

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 c2be2f1..b4f40ff 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -2416,6 +2416,10 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
                         .reduce(WideningCategories::lowestUpperBound)
                         .filter(returnType -> !returnType.equals(OBJECT_TYPE))
                         .ifPresent(returnType -> storeType(expression, wrapClosureType(returnType)));
+            } else if (!(expression instanceof MethodReferenceExpression)) {
+                ClassNode type = wrapTypeIfNecessary(getType(expression.getExpression()));
+                if (isClassClassNodeWrappingConcreteType(type)) type = type.getGenericsTypes()[0].getType();
+                addStaticTypeError("Cannot find matching method " + type.getText() + "#" + nameText + ". Please check if the declared type is correct and if the method exists.", nameExpr);
             }
         }
     }
diff --git a/src/test/groovy/transform/stc/BugsSTCTest.groovy b/src/test/groovy/transform/stc/BugsSTCTest.groovy
index a0f21f9..fda9633 100644
--- a/src/test/groovy/transform/stc/BugsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/BugsSTCTest.groovy
@@ -820,7 +820,7 @@ Printer
         '''
     }
 
-    //GROOVY-8590
+    // GROOVY-8590
     void testNestedMethodCallInferredTypeInReturnStmt() {
         assertScript '''
             class Source {
@@ -833,4 +833,10 @@ Printer
         '''
     }
 
+    // GROOVY-9463
+    void testMethodPointerUnknownReference() {
+        shouldFailWithMessages '''
+            def ptr = String.&toLowerCaseX
+        ''', 'Cannot find matching method java.lang.String#toLowerCaseX.'
+    }
 }