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 2021/03/21 18:59:40 UTC
[groovy] branch GROOVY_3_0_X updated: GROOVY-9977: share logic for
functional interface assignment
This is an automated email from the ASF dual-hosted git repository.
emilles pushed a commit to branch GROOVY_3_0_X
in repository https://gitbox.apache.org/repos/asf/groovy.git
The following commit(s) were added to refs/heads/GROOVY_3_0_X by this push:
new 67e5987 GROOVY-9977: share logic for functional interface assignment
67e5987 is described below
commit 67e59877e906dc4211794f869f896ab07aada6f0
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Sun Mar 21 13:30:36 2021 -0500
GROOVY-9977: share logic for functional interface assignment
---
.../transform/stc/StaticTypeCheckingVisitor.java | 51 ++++++++++++----------
src/test/groovy/transform/stc/LambdaTest.groovy | 37 ++++++++++++++++
2 files changed, 66 insertions(+), 22 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 abe3fce..e6e3fd2 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -745,25 +745,15 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
if (ensureValidSetter(expression, leftExpression, rightExpression, setterInfo)) {
return;
}
+ lType = getType(leftExpression);
} else {
lType = getType(leftExpression);
- boolean isFunctionalInterface = isFunctionalInterface(lType);
- if (isFunctionalInterface && rightExpression instanceof MethodReferenceExpression) {
- LambdaExpression lambdaExpression = constructLambdaExpressionForMethodReference(lType);
- if (op == ASSIGN) {
- inferParameterAndReturnTypesOfClosureOnRHS(lType, lambdaExpression);
- }
- rightExpression.putNodeMetaData(CONSTRUCTED_LAMBDA_EXPRESSION, lambdaExpression);
- rightExpression.putNodeMetaData(CLOSURE_ARGUMENTS, Arrays.stream(lambdaExpression.getParameters()).map(Parameter::getType).toArray(ClassNode[]::new));
-
- } else if (op == ASSIGN && isFunctionalInterface && rightExpression instanceof ClosureExpression) {
- inferParameterAndReturnTypesOfClosureOnRHS(lType, (ClosureExpression) rightExpression);
+ if (op == ASSIGN && isFunctionalInterface(lType)) {
+ processFunctionalInterfaceAssignment(lType, rightExpression);
}
-
rightExpression.visit(this);
}
- if (lType == null) lType = getType(leftExpression);
ClassNode rType = isNullConstant(rightExpression) && !isPrimitiveType(lType)
? UNKNOWN_PARAMETER_TYPE // null to primitive type is handled elsewhere
: getInferredTypeFromTempInfo(rightExpression, getType(rightExpression));
@@ -913,6 +903,18 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
}
}
+ private void processFunctionalInterfaceAssignment(final ClassNode lhsType, final Expression rhsExpression) {
+ if (rhsExpression instanceof ClosureExpression) {
+ inferParameterAndReturnTypesOfClosureOnRHS(lhsType, (ClosureExpression) rhsExpression);
+ } else if (rhsExpression instanceof MethodReferenceExpression) {
+ LambdaExpression lambdaExpression = constructLambdaExpressionForMethodReference(lhsType);
+
+ inferParameterAndReturnTypesOfClosureOnRHS(lhsType, lambdaExpression);
+ rhsExpression.putNodeMetaData(CONSTRUCTED_LAMBDA_EXPRESSION, lambdaExpression);
+ rhsExpression.putNodeMetaData(CLOSURE_ARGUMENTS, Arrays.stream(lambdaExpression.getParameters()).map(Parameter::getType).toArray(ClassNode[]::new));
+ }
+ }
+
private void inferParameterAndReturnTypesOfClosureOnRHS(final ClassNode lhsType, final ClosureExpression rhsExpression) {
Tuple2<ClassNode[], ClassNode> typeInfo = GenericsUtils.parameterizeSAM(lhsType);
Parameter[] closureParameters = getParametersSafe(rhsExpression);
@@ -1815,7 +1817,9 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
try {
typeCheckingContext.isInStaticContext = node.isInStaticContext();
currentProperty = node;
- super.visitProperty(node);
+ visitAnnotations(node);
+ visitClassCodeContainer(node.getGetterBlock());
+ visitClassCodeContainer(node.getSetterBlock());
} finally {
currentProperty = null;
typeCheckingContext.isInStaticContext = osc;
@@ -1828,19 +1832,22 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
try {
typeCheckingContext.isInStaticContext = node.isInStaticContext();
currentField = node;
- super.visitField(node);
+ visitAnnotations(node);
Expression init = node.getInitialExpression();
if (init != null) {
- FieldExpression left = new FieldExpression(node);
- BinaryExpression bexp = assignX(left, init, node);
- ClassNode lType = getType(node), rType = getType(init);
- typeCheckAssignment(bexp, left, lType, init, getResultType(lType, ASSIGN, rType, bexp));
-
+ ClassNode lType = getType(node);
+ if (isFunctionalInterface(lType)) { // GROOVY-9977
+ processFunctionalInterfaceAssignment(lType, init);
+ }
+ init.visit(this);
+ ClassNode rType = getType(init);
if (init instanceof ConstructorCallExpression) {
inferDiamondType((ConstructorCallExpression) init, lType);
- } else if (init instanceof ClosureExpression && isFunctionalInterface(lType)) {
- inferParameterAndReturnTypesOfClosureOnRHS(lType, (ClosureExpression) init);
}
+
+ FieldExpression left = new FieldExpression(node);
+ BinaryExpression bexp = assignX(left, init, node);
+ typeCheckAssignment(bexp, left, lType, init, getResultType(lType, ASSIGN, rType, bexp));
}
} finally {
currentField = null;
diff --git a/src/test/groovy/transform/stc/LambdaTest.groovy b/src/test/groovy/transform/stc/LambdaTest.groovy
index af9458c..9d6763e 100644
--- a/src/test/groovy/transform/stc/LambdaTest.groovy
+++ b/src/test/groovy/transform/stc/LambdaTest.groovy
@@ -294,6 +294,43 @@ final class LambdaTest {
}
@Test
+ void testComparator1() {
+ assertScript '''
+ @groovy.transform.CompileStatic class T {
+ Comparator<Integer> c = (Integer a, Integer b) -> Integer.compare(a, b)
+ }
+ def t = new T()
+ assert t.c.compare(0,0) == 0
+ '''
+
+ def err = shouldFail '''
+ @groovy.transform.CompileStatic class T {
+ Comparator<Integer> c = (int a, int b) -> Integer.compare(a, b)
+ }
+ '''
+ assert err =~ /Cannot assign java.util.Comparator <int> to: java.util.Comparator <Integer>/
+ }
+
+ @Test // GROOVY-9977
+ void testComparator2() {
+ assertScript '''
+ @groovy.transform.CompileStatic
+ class T {
+ Comparator<Integer> c = (a, b) -> Integer.compare(a, b)
+
+ static void m1() {
+ Comparator<Integer> x = (a, b) -> Integer.compare(a, b)
+ }
+ void m2() {
+ Comparator<Integer> y = (a, b) -> Integer.compare(a, b)
+ }
+ }
+ def t = new T()
+ assert t.c.compare(0,0) == 0
+ '''
+ }
+
+ @Test
void testFunctionWithLocalVariables() {
assertScript '''
import groovy.transform.CompileStatic