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/02 00:21:28 UTC
[groovy] branch GROOVY_2_5_X 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 GROOVY_2_5_X
in repository https://gitbox.apache.org/repos/asf/groovy.git
The following commit(s) were added to refs/heads/GROOVY_2_5_X by this push:
new 94d025d105 GROOVY-7141: STC: infer param types for closure map to SAM-type coercion
94d025d105 is described below
commit 94d025d1058f5922a0849089d9da94556005113c
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Tue Nov 1 17:39:03 2022 -0500
GROOVY-7141: STC: infer param types for closure map to SAM-type coercion
2_5_X backport
---
.../transform/stc/StaticTypeCheckingVisitor.java | 25 +++++++++++++----
.../stc/ClosureParamTypeInferenceSTCTest.groovy | 32 +++++++++++++++++++++-
2 files changed, 50 insertions(+), 7 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 0bb117352f..f3d39449ff 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -647,7 +647,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
}
if (variable != null) {
ClassNode inferredType = getInferredTypeFromTempInfo(variable, (ClassNode) variable.getNodeMetaData(StaticTypesMarker.INFERRED_TYPE));
- if (inferredType != null && !inferredType.getName().equals(ClassHelper.OBJECT) && !inferredType.equals(accessedVariable.getType())) {
+ if (inferredType != null && !inferredType.getName().equals(ClassHelper.OBJECT) && !inferredType.equals(accessedVariable.getOriginType())) {
vexp.putNodeMetaData(StaticTypesMarker.INFERRED_RETURN_TYPE, inferredType);
}
}
@@ -1033,6 +1033,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
private void processFunctionalInterfaceAssignment(final ClassNode lhsType, final Expression rhsExpression) {
if (rhsExpression instanceof ClosureExpression) {
MethodNode abstractMethod = findSAM(lhsType);
+ ClosureExpression closure = (ClosureExpression) rhsExpression;
Map<GenericsType, GenericsType> mappings = GenericsUtils.makeDeclaringAndActualGenericsTypeMapOfExactType(abstractMethod.getDeclaringClass(), lhsType);
ClassNode[] samParameterTypes = extractTypesFromParameters(abstractMethod.getParameters());
@@ -1042,13 +1043,18 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
}
}
- Parameter[] closureParameters = getParametersSafe((ClosureExpression) rhsExpression);
- if (closureParameters.length == samParameterTypes.length || (1 == samParameterTypes.length && hasImplicitParameter((ClosureExpression) rhsExpression))) {
- for (int i = 0; i < closureParameters.length; i += 1) {
+ Parameter[] closureParameters = getParametersSafe(closure);
+ if (samParameterTypes.length == 1 && hasImplicitParameter(closure)) {
+ Variable it = closure.getVariableScope().getDeclaredVariable("it"); // GROOVY-7141
+ closureParameters = new Parameter[] {it instanceof Parameter ? (Parameter) it : new Parameter(DYNAMIC_TYPE, "")};
+ }
+
+ 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 {
@@ -1061,6 +1067,13 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
returnType = GenericsUtils.findActualTypeByGenericsPlaceholderName(returnType.getUnresolvedName(), mappings);
}
storeInferredReturnType(rhsExpression, returnType);
+
+ } else if (rhsExpression instanceof MapExpression) { // GROOVY-7141
+ List<MapEntryExpression> spec = ((MapExpression) rhsExpression).getMapEntryExpressions();
+ if (spec.size() == 1 && spec.get(0).getValueExpression() instanceof ClosureExpression
+ && findSAM(lhsType).getName().equals(spec.get(0).getKeyExpression().getText())) {
+ processFunctionalInterfaceAssignment(lhsType, spec.get(0).getValueExpression());
+ }
}
}
@@ -5918,7 +5931,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
this.parameter = parameter;
ClassNode inferredType = getNodeMetaData(StaticTypesMarker.INFERRED_TYPE);
if (inferredType == null) {
- setNodeMetaData(StaticTypesMarker.INFERRED_TYPE, parameter.getOriginType());
+ setNodeMetaData(StaticTypesMarker.INFERRED_TYPE, parameter.getType());
}
}
diff --git a/src/test/groovy/transform/stc/ClosureParamTypeInferenceSTCTest.groovy b/src/test/groovy/transform/stc/ClosureParamTypeInferenceSTCTest.groovy
index 2246d15f42..44bfbfea47 100644
--- a/src/test/groovy/transform/stc/ClosureParamTypeInferenceSTCTest.groovy
+++ b/src/test/groovy/transform/stc/ClosureParamTypeInferenceSTCTest.groovy
@@ -1181,7 +1181,37 @@ class ClosureParamTypeInferenceSTCTest extends StaticTypeCheckingTestCase {
'''
}
- 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 '''import java.util.concurrent.Callable
interface Action<T> {
void execute(T thing)