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 2020/09/21 19:11:54 UTC
[groovy] 01/03: GROOVY-9751: STC: add inferencing of method
pointer/reference expression
This is an automated email from the ASF dual-hosted git repository.
emilles pushed a commit to branch GROOVY-9751
in repository https://gitbox.apache.org/repos/asf/groovy.git
commit 982a48b13f6f5aa311aea9ef0f711e48adc4399b
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