Skip to content

Commit 04b56fd

Browse files
committed
GROOVY-7141
1 parent 47d6c6b commit 04b56fd

File tree

5 files changed

+102
-21
lines changed

5 files changed

+102
-21
lines changed

base-test/org.eclipse.jdt.groovy.core.tests.compiler/src/org/eclipse/jdt/groovy/core/tests/xform/StaticCompilationTests.java

+24
Original file line numberDiff line numberDiff line change
@@ -778,6 +778,30 @@ public void testCompileStatic29() {
778778
runConformTest(sources);
779779
}
780780

781+
@Test
782+
public void testCompileStatic30() {
783+
assumeTrue(isParrotParser());
784+
785+
//@formatter:off
786+
String[] sources = {
787+
"Main.groovy",
788+
"import java.util.function.Function\n" +
789+
"@groovy.transform.CompileStatic\n" +
790+
"void test() {\n" +
791+
" Function<String, String> lower = String::toLowerCase\n" +
792+
" Function<String, String> upper = String::toUpperCase\n" +
793+
" Function<String, String> lu = lower.andThen(upper)\n" +
794+
" Function<? super String, String> ul = upper.andThen(lower)\n" +
795+
" assert lower('Hi') == ul('Hi')\n" +
796+
" assert upper('Hi') == lu('Hi')\n" +
797+
"}\n" +
798+
"test()\n",
799+
};
800+
//@formatter:on
801+
802+
runConformTest(sources);
803+
}
804+
781805
@Test
782806
public void testCompileStatic1505() {
783807
//@formatter:off

base-test/org.eclipse.jdt.groovy.core.tests.compiler/src/org/eclipse/jdt/groovy/core/tests/xform/TypeCheckedTests.java

+24
Original file line numberDiff line numberDiff line change
@@ -1334,6 +1334,30 @@ public void testTypeChecked7128d() {
13341334
runConformTest(sources);
13351335
}
13361336

1337+
@Test
1338+
public void testTypeChecked7141() {
1339+
//@formatter:off
1340+
String[] sources = {
1341+
"Main.groovy",
1342+
"import groovy.transform.*\n" +
1343+
"@PackageScope\n" +
1344+
"interface I {\n" +
1345+
" String f(String s)\n" +
1346+
"}\n" +
1347+
"@TypeChecked\n" +
1348+
"void test(){\n" +
1349+
" I impl = [\n" +
1350+
" f: { it.toUpperCase() }\n" + // parameter type not inferred for coerced map
1351+
" ] as I\n" +
1352+
" print impl.f('works')\n" +
1353+
"}\n" +
1354+
"test()\n",
1355+
};
1356+
//@formatter:on
1357+
1358+
runConformTest(sources, "WORKS");
1359+
}
1360+
13371361
@Test
13381362
public void testTypeChecked7164() {
13391363
//@formatter:off

base/org.codehaus.groovy25/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java

+19-6
Original file line numberDiff line numberDiff line change
@@ -667,7 +667,7 @@ public void visitVariableExpression(VariableExpression vexp) {
667667
}
668668
if (variable != null) {
669669
ClassNode inferredType = getInferredTypeFromTempInfo(variable, (ClassNode) variable.getNodeMetaData(StaticTypesMarker.INFERRED_TYPE));
670-
if (inferredType != null && !inferredType.getName().equals(ClassHelper.OBJECT) && !inferredType.equals(accessedVariable.getType())) {
670+
if (inferredType != null && !inferredType.getName().equals(ClassHelper.OBJECT) && !inferredType.equals(accessedVariable.getOriginType())) {
671671
/* GRECLIPSE edit -- GROOVY-10308
672672
vexp.putNodeMetaData(StaticTypesMarker.INFERRED_RETURN_TYPE, inferredType);
673673
*/
@@ -1055,6 +1055,7 @@ private static boolean isFunctionalInterface(final ClassNode type) {
10551055
private void processFunctionalInterfaceAssignment(final ClassNode lhsType, final Expression rhsExpression) {
10561056
if (rhsExpression instanceof ClosureExpression) {
10571057
MethodNode abstractMethod = findSAM(lhsType);
1058+
ClosureExpression closure = (ClosureExpression) rhsExpression;
10581059
Map<GenericsType, GenericsType> mappings = GenericsUtils.makeDeclaringAndActualGenericsTypeMapOfExactType(abstractMethod.getDeclaringClass(), lhsType);
10591060

10601061
ClassNode[] samParameterTypes = extractTypesFromParameters(abstractMethod.getParameters());
@@ -1064,13 +1065,18 @@ private void processFunctionalInterfaceAssignment(final ClassNode lhsType, final
10641065
}
10651066
}
10661067

1067-
Parameter[] closureParameters = getParametersSafe((ClosureExpression) rhsExpression);
1068-
if (closureParameters.length == samParameterTypes.length || (1 == samParameterTypes.length && hasImplicitParameter((ClosureExpression) rhsExpression))) {
1069-
for (int i = 0; i < closureParameters.length; i += 1) {
1068+
Parameter[] closureParameters = getParametersSafe(closure);
1069+
if (samParameterTypes.length == 1 && hasImplicitParameter(closure)) {
1070+
Variable it = closure.getVariableScope().getDeclaredVariable("it"); // GROOVY-7141
1071+
closureParameters = new Parameter[] {it instanceof Parameter ? (Parameter) it : new Parameter(DYNAMIC_TYPE, "")};
1072+
}
1073+
1074+
int n = closureParameters.length;
1075+
if (n == samParameterTypes.length) {
1076+
for (int i = 0; i < n; i += 1) {
10701077
Parameter parameter = closureParameters[i];
10711078
if (parameter.isDynamicTyped()) {
10721079
parameter.setType(samParameterTypes[i]);
1073-
parameter.setOriginType(samParameterTypes[i]);
10741080
}
10751081
}
10761082
} else {
@@ -1083,6 +1089,13 @@ private void processFunctionalInterfaceAssignment(final ClassNode lhsType, final
10831089
returnType = GenericsUtils.findActualTypeByGenericsPlaceholderName(returnType.getUnresolvedName(), mappings);
10841090
}
10851091
storeInferredReturnType(rhsExpression, returnType);
1092+
1093+
} else if (rhsExpression instanceof MapExpression) { // GROOVY-7141
1094+
List<MapEntryExpression> spec = ((MapExpression) rhsExpression).getMapEntryExpressions();
1095+
if (spec.size() == 1 && spec.get(0).getValueExpression() instanceof ClosureExpression
1096+
&& findSAM(lhsType).getName().equals(spec.get(0).getKeyExpression().getText())) {
1097+
processFunctionalInterfaceAssignment(lhsType, spec.get(0).getValueExpression());
1098+
}
10861099
}
10871100
}
10881101

@@ -6828,7 +6841,7 @@ private class ParameterVariableExpression extends VariableExpression {
68286841
ClassNode inferredType = getNodeMetaData(StaticTypesMarker.INFERRED_TYPE);
68296842
if (inferredType == null) {
68306843
/* GRECLIPSE edit -- GROOVY-10651, GROOVY-10673
6831-
setNodeMetaData(StaticTypesMarker.INFERRED_TYPE, parameter.getOriginType());
6844+
setNodeMetaData(StaticTypesMarker.INFERRED_TYPE, parameter.getType());
68326845
*/
68336846
inferredType = typeCheckingContext.controlStructureVariables.get(parameter); // for/catch/closure
68346847
if (inferredType == null) {

base/org.codehaus.groovy30/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java

+15-5
Original file line numberDiff line numberDiff line change
@@ -663,7 +663,7 @@ public void visitVariableExpression(final VariableExpression vexp) {
663663
ClassNode inferredType = localVariable.getNodeMetaData(INFERRED_TYPE);
664664
inferredType = getInferredTypeFromTempInfo(localVariable, inferredType);
665665
if (inferredType != null && !inferredType.equals(OBJECT_TYPE)
666-
&& !inferredType.equals(accessedVariable.getType())){
666+
&& !inferredType.equals(accessedVariable.getOriginType())) {
667667
/* GRECLIPSE edit -- GROOVY-10308
668668
vexp.putNodeMetaData(INFERRED_RETURN_TYPE, inferredType);
669669
*/
@@ -940,6 +940,12 @@ private void validateResourceInARM(final BinaryExpression expression, final Clas
940940
private void processFunctionalInterfaceAssignment(final ClassNode lhsType, final Expression rhsExpression) {
941941
if (rhsExpression instanceof ClosureExpression) {
942942
inferParameterAndReturnTypesOfClosureOnRHS(lhsType, (ClosureExpression) rhsExpression);
943+
} else if (rhsExpression instanceof MapExpression) { // GROOVY-7141
944+
List<MapEntryExpression> spec = ((MapExpression) rhsExpression).getMapEntryExpressions();
945+
if (spec.size() == 1 && spec.get(0).getValueExpression() instanceof ClosureExpression
946+
&& findSAM(lhsType).getName().equals(spec.get(0).getKeyExpression().getText())) {
947+
inferParameterAndReturnTypesOfClosureOnRHS(lhsType, (ClosureExpression) spec.get(0).getValueExpression());
948+
}
943949
} else if (rhsExpression instanceof MethodReferenceExpression) {
944950
LambdaExpression lambdaExpression = constructLambdaExpressionForMethodReference(lhsType, (MethodReferenceExpression) rhsExpression);
945951

@@ -954,14 +960,18 @@ private void inferParameterAndReturnTypesOfClosureOnRHS(final ClassNode lhsType,
954960
Parameter[] closureParameters = getParametersSafe(rhsExpression);
955961
ClassNode[] samParameterTypes = typeInfo.getV1();
956962

957-
int n = closureParameters.length, m = samParameterTypes.length;
958-
if (n == m || (1 == m && hasImplicitParameter(rhsExpression))) {
963+
if (samParameterTypes.length == 1 && hasImplicitParameter(rhsExpression)) {
964+
Variable it = rhsExpression.getVariableScope().getDeclaredVariable("it"); // GROOVY-7141
965+
closureParameters = new Parameter[] {it instanceof Parameter ? (Parameter) it : new Parameter(DYNAMIC_TYPE, "")};
966+
}
967+
968+
int n = closureParameters.length;
969+
if (n == samParameterTypes.length) {
959970
for (int i = 0; i < n; i += 1) {
960971
if (samParameterTypes[i] == null) continue;
961972
Parameter parameter = closureParameters[i];
962973
if (parameter.isDynamicTyped()) {
963974
parameter.setType(samParameterTypes[i]);
964-
parameter.setOriginType(samParameterTypes[i]);
965975
}
966976
}
967977
} else {
@@ -6571,7 +6581,7 @@ private class ParameterVariableExpression extends VariableExpression {
65716581
super(parameter);
65726582
this.parameter = parameter;
65736583
/* GRECLIPSE edit -- GROOVY-10651
6574-
this.parameter.getNodeMetaData(INFERRED_TYPE, x -> parameter.getOriginType());
6584+
this.parameter.getNodeMetaData(INFERRED_TYPE, x -> parameter.getType());
65756585
*/
65766586
ClassNode inferredType = getNodeMetaData(INFERRED_TYPE);
65776587
if (inferredType == null) {

base/org.codehaus.groovy40/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java

+20-10
Original file line numberDiff line numberDiff line change
@@ -668,7 +668,7 @@ public void visitVariableExpression(final VariableExpression vexp) {
668668

669669
ClassNode inferredType = localVariable.getNodeMetaData(INFERRED_TYPE);
670670
inferredType = getInferredTypeFromTempInfo(localVariable, inferredType);
671-
if (inferredType != null && !isObjectType(inferredType) && !inferredType.equals(accessedVariable.getType())) {
671+
if (inferredType != null && !isObjectType(inferredType) && !inferredType.equals(accessedVariable.getOriginType())) {
672672
vexp.putNodeMetaData(INFERRED_TYPE, inferredType);
673673
}
674674
}
@@ -933,21 +933,27 @@ private void validateResourceInARM(final BinaryExpression expression, final Clas
933933
}
934934

935935
private void applyTargetType(final ClassNode target, final Expression source) {
936-
if (isFunctionalInterface(target)) {
936+
if (isClosureWithType(target)) {
937+
if (source instanceof ClosureExpression) {
938+
GenericsType returnType = target.getGenericsTypes()[0];
939+
storeInferredReturnType(source, getCombinedBoundType(returnType));
940+
}
941+
} else if (isFunctionalInterface(target)) {
937942
if (source instanceof ClosureExpression) {
938943
inferParameterAndReturnTypesOfClosureOnRHS(target, (ClosureExpression) source);
944+
} else if (source instanceof MapExpression) { // GROOVY-7141
945+
List<MapEntryExpression> spec = ((MapExpression) source).getMapEntryExpressions();
946+
if (spec.size() == 1 && spec.get(0).getValueExpression() instanceof ClosureExpression
947+
&& findSAM(target).getName().equals(spec.get(0).getKeyExpression().getText())) {
948+
inferParameterAndReturnTypesOfClosureOnRHS(target, (ClosureExpression) spec.get(0).getValueExpression());
949+
}
939950
} else if (source instanceof MethodReferenceExpression) {
940951
LambdaExpression lambdaExpression = constructLambdaExpressionForMethodReference(target, (MethodReferenceExpression) source);
941952

942953
inferParameterAndReturnTypesOfClosureOnRHS(target, lambdaExpression);
943954
source.putNodeMetaData(CONSTRUCTED_LAMBDA_EXPRESSION, lambdaExpression);
944955
source.putNodeMetaData(CLOSURE_ARGUMENTS, Arrays.stream(lambdaExpression.getParameters()).map(Parameter::getType).toArray(ClassNode[]::new));
945956
}
946-
} else if (isClosureWithType(target)) {
947-
if (source instanceof ClosureExpression) {
948-
GenericsType returnType = target.getGenericsTypes()[0];
949-
storeInferredReturnType(source, getCombinedBoundType(returnType));
950-
}
951957
}
952958
}
953959

@@ -956,13 +962,17 @@ private void inferParameterAndReturnTypesOfClosureOnRHS(final ClassNode lhsType,
956962
Parameter[] closureParameters = getParametersSafe(rhsExpression);
957963
ClassNode[] samParameterTypes = typeInfo.getV1();
958964

959-
int n = closureParameters.length, m = samParameterTypes.length;
960-
if (n == m || (1 == m && hasImplicitParameter(rhsExpression))) {
965+
if (samParameterTypes.length == 1 && hasImplicitParameter(rhsExpression)) {
966+
Variable it = rhsExpression.getVariableScope().getDeclaredVariable("it"); // GROOVY-7141
967+
closureParameters = new Parameter[]{it instanceof Parameter ? (Parameter) it : new Parameter(dynamicType(), "")};
968+
}
969+
970+
int n = closureParameters.length;
971+
if (n == samParameterTypes.length) {
961972
for (int i = 0; i < n; i += 1) {
962973
Parameter parameter = closureParameters[i];
963974
if (parameter.isDynamicTyped()) {
964975
parameter.setType(samParameterTypes[i]);
965-
parameter.setOriginType(samParameterTypes[i]);
966976
} else {
967977
checkParamType(parameter, samParameterTypes[i], i == n-1, rhsExpression instanceof LambdaExpression);
968978
}

0 commit comments

Comments
 (0)