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/11/01 16:33:59 UTC
[groovy] branch master updated: GROOVY-7141: STC: infer param types for closure map to SAM-type coercion
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 db1e25b468 GROOVY-7141: STC: infer param types for closure map to SAM-type coercion
db1e25b468 is described below
commit db1e25b4682d665d589caaaf18d6867de64d2612
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Tue Nov 1 11:28:09 2022 -0500
GROOVY-7141: STC: infer param types for closure map to SAM-type coercion
---
.../transform/stc/StaticTypeCheckingVisitor.java | 30 +++++++++++++-------
.../stc/ClosureParamTypeInferenceSTCTest.groovy | 32 +++++++++++++++++++++-
2 files changed, 51 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 e3997e0303..37d7934f21 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -711,7 +711,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
ClassNode inferredType = localVariable.getNodeMetaData(INFERRED_TYPE);
inferredType = getInferredTypeFromTempInfo(localVariable, inferredType);
- if (inferredType != null && !isObjectType(inferredType) && !inferredType.equals(accessedVariable.getType())) {
+ if (inferredType != null && !isObjectType(inferredType) && !inferredType.equals(accessedVariable.getOriginType())) {
vexp.putNodeMetaData(INFERRED_TYPE, inferredType);
}
}
@@ -964,9 +964,20 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
}
private void applyTargetType(final ClassNode target, final Expression source) {
- if (isFunctionalInterface(target)) {
+ if (isClosureWithType(target)) {
+ if (source instanceof ClosureExpression) {
+ GenericsType returnType = target.getGenericsTypes()[0];
+ storeInferredReturnType(source, getCombinedBoundType(returnType));
+ }
+ } else if (isFunctionalInterface(target)) {
if (source instanceof ClosureExpression) {
inferParameterAndReturnTypesOfClosureOnRHS(target, (ClosureExpression) source);
+ } else if (source instanceof MapExpression) { // GROOVY-7141
+ List<MapEntryExpression> spec = ((MapExpression) source).getMapEntryExpressions();
+ if (spec.size() == 1 && spec.get(0).getValueExpression() instanceof ClosureExpression
+ && findSAM(target).getName().equals(spec.get(0).getKeyExpression().getText())) {
+ inferParameterAndReturnTypesOfClosureOnRHS(target, (ClosureExpression) spec.get(0).getValueExpression());
+ }
} else if (source instanceof MethodReferenceExpression) {
LambdaExpression lambdaExpression = constructLambdaExpressionForMethodReference(target, (MethodReferenceExpression) source);
@@ -974,11 +985,6 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
source.putNodeMetaData(CONSTRUCTED_LAMBDA_EXPRESSION, lambdaExpression);
source.putNodeMetaData(CLOSURE_ARGUMENTS, Arrays.stream(lambdaExpression.getParameters()).map(Parameter::getType).toArray(ClassNode[]::new));
}
- } else if (isClosureWithType(target)) {
- if (source instanceof ClosureExpression) {
- GenericsType returnType = target.getGenericsTypes()[0];
- storeInferredReturnType(source, getCombinedBoundType(returnType));
- }
}
}
@@ -987,13 +993,17 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
Parameter[] closureParameters = getParametersSafe(rhsExpression);
ClassNode[] samParameterTypes = typeInfo.getV1();
- int n = closureParameters.length, m = samParameterTypes.length;
- if (n == m || (1 == m && hasImplicitParameter(rhsExpression))) {
+ if (samParameterTypes.length == 1 && hasImplicitParameter(rhsExpression)) {
+ Variable it = rhsExpression.getVariableScope().getDeclaredVariable("it"); // GROOVY-7141
+ closureParameters = new Parameter[]{it instanceof Parameter ? (Parameter) it : new Parameter(dynamicType(), "")};
+ }
+
+ int n = closureParameters.length;
+ if (n == samParameterTypes.length) {
for (int i = 0; i < n; i += 1) {
Parameter parameter = closureParameters[i];
if (parameter.isDynamicTyped()) {
parameter.setType(samParameterTypes[i]);
- parameter.setOriginType(samParameterTypes[i]);
} else {
checkParamType(parameter, samParameterTypes[i], i == n-1, rhsExpression instanceof LambdaExpression);
}
diff --git a/src/test/groovy/transform/stc/ClosureParamTypeInferenceSTCTest.groovy b/src/test/groovy/transform/stc/ClosureParamTypeInferenceSTCTest.groovy
index e1e889f7e4..2537b14226 100644
--- a/src/test/groovy/transform/stc/ClosureParamTypeInferenceSTCTest.groovy
+++ b/src/test/groovy/transform/stc/ClosureParamTypeInferenceSTCTest.groovy
@@ -1293,7 +1293,37 @@ class ClosureParamTypeInferenceSTCTest extends StaticTypeCheckingTestCase {
'Incorrect number of parameters. Expected 1 but found 2'
}
- void testInferenceWithSAMTypeCoercion() {
+ // GROOVY-7141
+ void testInferenceWithSAMTypeCoercion1() {
+ String sam = '''
+ @FunctionalInterface
+ interface I {
+ String foo(String s)
+ }
+ '''
+ assertScript sam + '''
+ def impl = [foo: { it.toUpperCase() }] as I
+ String result = impl.foo('bar')
+ assert result == 'BAR'
+ '''
+ assertScript sam + '''
+ def impl = [foo: { s -> s.toUpperCase() }] as I
+ String result = impl.foo('bar')
+ assert result == 'BAR'
+ '''
+ assertScript sam + '''
+ def impl = [foo: { String s -> s.toUpperCase() }] as I
+ String result = impl.foo('bar')
+ assert result == 'BAR'
+ '''
+ assertScript '''
+ def impl = [apply: { it.toUpperCase() }] as java.util.function.Function<String,String>
+ String result = impl.apply('bar')
+ assert result == 'BAR'
+ '''
+ }
+
+ void testInferenceWithSAMTypeCoercion2() {
assertScript '''
interface Action<T> {
void execute(T thing)