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/09/03 16:28:45 UTC
[groovy] branch master updated: GROOVY-10734: STC: `Type::instanceMethod` specifies first param type
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
The following commit(s) were added to refs/heads/master by this push:
new 9bffe17a68 GROOVY-10734: STC: `Type::instanceMethod` specifies first param type
9bffe17a68 is described below
commit 9bffe17a6831fedd7eeb62ace9b8a920b1451278
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Sat Sep 3 11:17:37 2022 -0500
GROOVY-10734: STC: `Type::instanceMethod` specifies first param type
---
.../transform/stc/StaticTypeCheckingVisitor.java | 32 +++++++++++++++-------
.../transform/stc/MethodReferenceTest.groovy | 18 ++++++++++++
2 files changed, 40 insertions(+), 10 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 378e63cfc8..2fb02586d5 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -924,7 +924,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
if (source instanceof ClosureExpression) {
inferParameterAndReturnTypesOfClosureOnRHS(target, (ClosureExpression) source);
} else if (source instanceof MethodReferenceExpression) {
- LambdaExpression lambdaExpression = constructLambdaExpressionForMethodReference(target);
+ LambdaExpression lambdaExpression = constructLambdaExpressionForMethodReference(target, (MethodReferenceExpression) source);
inferParameterAndReturnTypesOfClosureOnRHS(target, lambdaExpression);
source.putNodeMetaData(CONSTRUCTED_LAMBDA_EXPRESSION, lambdaExpression);
@@ -3684,7 +3684,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
newArgumentExpressions.add(argumentExpression);
} else {
methodReferencePositions.add(i);
- newArgumentExpressions.add(constructLambdaExpressionForMethodReference(paramType));
+ newArgumentExpressions.add(constructLambdaExpressionForMethodReference(paramType, (MethodReferenceExpression) argumentExpression));
}
}
}
@@ -3700,14 +3700,26 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
}
}
- private LambdaExpression constructLambdaExpressionForMethodReference(final ClassNode functionalInterfaceType) {
- int nParameters = findSAM(functionalInterfaceType).getParameters().length;
- Parameter[] parameters = new Parameter[nParameters];
- for (int i = 0; i < nParameters; i += 1) {
- parameters[i] = new Parameter(dynamicType(), "p" + i);
+ private LambdaExpression constructLambdaExpressionForMethodReference(final ClassNode functionalInterfaceType, final MethodReferenceExpression methodReference) {
+ Parameter[] parameters = findSAM(functionalInterfaceType).getParameters();
+ int nParameters = parameters.length;
+ if (nParameters > 0) {
+ ClassNode firstParamType = dynamicType();
+ // GROOVY-10734: Type::instanceMethod has implied first param
+ List<MethodNode> candidates = methodReference.getNodeMetaData(MethodNode.class);
+ if (candidates != null && !candidates.isEmpty()) {
+ ClassNode objExpType = getType(methodReference.getExpression());
+ if (isClassClassNodeWrappingConcreteType(objExpType)
+ && candidates.stream().allMatch(mn -> !mn.isStatic())) {
+ firstParamType = objExpType.getGenericsTypes()[0].getType();
+ }
+ }
+ parameters = new Parameter[nParameters];
+ for (int i = 0; i < nParameters; i += 1) {
+ parameters[i] = new Parameter(i == 0 ? firstParamType : dynamicType(), "p" + i);
+ }
}
-
- return new LambdaExpression(parameters, EmptyStatement.INSTANCE);
+ return new LambdaExpression(parameters, GENERATED_EMPTY_STATEMENT);
}
/**
@@ -5634,7 +5646,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
ClassNode[] paramTypes = applyGenericsContext(samTypeConnections, extractTypesFromParameters(parameters));
ClassNode[] matchTypes = candidates.stream()
.map(candidate -> collateMethodReferenceParameterTypes(mp, candidate))
- .filter(candidate -> checkSignatureSuitability(candidate, paramTypes))
+ .filter(signature -> checkSignatureSuitability(signature, paramTypes))
.findFirst().orElse(null); // TODO: order signatures by param distance
if (matchTypes != null) {
Map<GenericsTypeName, GenericsType> connections = new HashMap<>();
diff --git a/src/test/groovy/transform/stc/MethodReferenceTest.groovy b/src/test/groovy/transform/stc/MethodReferenceTest.groovy
index 8758987fc3..443e1a8126 100644
--- a/src/test/groovy/transform/stc/MethodReferenceTest.groovy
+++ b/src/test/groovy/transform/stc/MethodReferenceTest.groovy
@@ -216,6 +216,24 @@ final class MethodReferenceTest {
'''
}
+ @Test // class::instanceMethod -- GROOVY-10734
+ void testFunctionCI8() {
+ assertScript shell, '''
+ class C {
+ String p
+ }
+ @CompileStatic
+ Map test(Collection<C> items) {
+ items.stream().collect(
+ Collectors.groupingBy(C::getP) // Failed to find the expected method[getP(Object)] in the type[C]
+ )
+ }
+ def map = test([new C(p:'foo'), new C(p:'bar'), new C(p:'foo')])
+ assert map.foo.size() == 2
+ assert map.bar.size() == 1
+ '''
+ }
+
@Test // class::instanceMethod -- GROOVY-9974
void testPredicateCI() {
assertScript shell, '''