This is an automated email from the ASF dual-hosted git repository. paulk pushed a commit to branch GROOVY_3_0_X in repository https://gitbox.apache.org/repos/asf/groovy.git
commit 70c068c5a13a319481d8b60d38edcbd5f2110062 Author: Eric Milles <[email protected]> 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 781439e..a46a355 100644 --- a/src/test/groovy/transform/stc/GenericsSTCTest.groovy +++ b/src/test/groovy/transform/stc/GenericsSTCTest.groovy @@ -592,6 +592,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
