Skip to content

Commit

Permalink
GROOVY-7141
Browse files Browse the repository at this point in the history
  • Loading branch information
eric-milles committed Nov 2, 2022
1 parent 47d6c6b commit 04b56fd
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -778,6 +778,30 @@ public void testCompileStatic29() {
runConformTest(sources);
}

@Test
public void testCompileStatic30() {
assumeTrue(isParrotParser());

//@formatter:off
String[] sources = {
"Main.groovy",
"import java.util.function.Function\n" +
"@groovy.transform.CompileStatic\n" +
"void test() {\n" +
" Function<String, String> lower = String::toLowerCase\n" +
" Function<String, String> upper = String::toUpperCase\n" +
" Function<String, String> lu = lower.andThen(upper)\n" +
" Function<? super String, String> ul = upper.andThen(lower)\n" +
" assert lower('Hi') == ul('Hi')\n" +
" assert upper('Hi') == lu('Hi')\n" +
"}\n" +
"test()\n",
};
//@formatter:on

runConformTest(sources);
}

@Test
public void testCompileStatic1505() {
//@formatter:off
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1334,6 +1334,30 @@ public void testTypeChecked7128d() {
runConformTest(sources);
}

@Test
public void testTypeChecked7141() {
//@formatter:off
String[] sources = {
"Main.groovy",
"import groovy.transform.*\n" +
"@PackageScope\n" +
"interface I {\n" +
" String f(String s)\n" +
"}\n" +
"@TypeChecked\n" +
"void test(){\n" +
" I impl = [\n" +
" f: { it.toUpperCase() }\n" + // parameter type not inferred for coerced map
" ] as I\n" +
" print impl.f('works')\n" +
"}\n" +
"test()\n",
};
//@formatter:on

runConformTest(sources, "WORKS");
}

@Test
public void testTypeChecked7164() {
//@formatter:off
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -667,7 +667,7 @@ public void visitVariableExpression(VariableExpression vexp) {
}
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())) {
/* GRECLIPSE edit -- GROOVY-10308
vexp.putNodeMetaData(StaticTypesMarker.INFERRED_RETURN_TYPE, inferredType);
*/
Expand Down Expand Up @@ -1055,6 +1055,7 @@ private static boolean isFunctionalInterface(final ClassNode type) {
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());
Expand All @@ -1064,13 +1065,18 @@ private void processFunctionalInterfaceAssignment(final ClassNode lhsType, final
}
}

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 {
Expand All @@ -1083,6 +1089,13 @@ private void processFunctionalInterfaceAssignment(final ClassNode lhsType, final
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());
}
}
}

Expand Down Expand Up @@ -6828,7 +6841,7 @@ private class ParameterVariableExpression extends VariableExpression {
ClassNode inferredType = getNodeMetaData(StaticTypesMarker.INFERRED_TYPE);
if (inferredType == null) {
/* GRECLIPSE edit -- GROOVY-10651, GROOVY-10673
setNodeMetaData(StaticTypesMarker.INFERRED_TYPE, parameter.getOriginType());
setNodeMetaData(StaticTypesMarker.INFERRED_TYPE, parameter.getType());
*/
inferredType = typeCheckingContext.controlStructureVariables.get(parameter); // for/catch/closure
if (inferredType == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -663,7 +663,7 @@ public void visitVariableExpression(final VariableExpression vexp) {
ClassNode inferredType = localVariable.getNodeMetaData(INFERRED_TYPE);
inferredType = getInferredTypeFromTempInfo(localVariable, inferredType);
if (inferredType != null && !inferredType.equals(OBJECT_TYPE)
&& !inferredType.equals(accessedVariable.getType())){
&& !inferredType.equals(accessedVariable.getOriginType())) {
/* GRECLIPSE edit -- GROOVY-10308
vexp.putNodeMetaData(INFERRED_RETURN_TYPE, inferredType);
*/
Expand Down Expand Up @@ -940,6 +940,12 @@ private void validateResourceInARM(final BinaryExpression expression, final Clas
private void processFunctionalInterfaceAssignment(final ClassNode lhsType, final Expression rhsExpression) {
if (rhsExpression instanceof ClosureExpression) {
inferParameterAndReturnTypesOfClosureOnRHS(lhsType, (ClosureExpression) rhsExpression);
} 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())) {
inferParameterAndReturnTypesOfClosureOnRHS(lhsType, (ClosureExpression) spec.get(0).getValueExpression());
}
} else if (rhsExpression instanceof MethodReferenceExpression) {
LambdaExpression lambdaExpression = constructLambdaExpressionForMethodReference(lhsType, (MethodReferenceExpression) rhsExpression);

Expand All @@ -954,14 +960,18 @@ private void inferParameterAndReturnTypesOfClosureOnRHS(final ClassNode lhsType,
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(DYNAMIC_TYPE, "")};
}

int n = closureParameters.length;
if (n == samParameterTypes.length) {
for (int i = 0; i < n; i += 1) {
if (samParameterTypes[i] == null) continue;
Parameter parameter = closureParameters[i];
if (parameter.isDynamicTyped()) {
parameter.setType(samParameterTypes[i]);
parameter.setOriginType(samParameterTypes[i]);
}
}
} else {
Expand Down Expand Up @@ -6571,7 +6581,7 @@ private class ParameterVariableExpression extends VariableExpression {
super(parameter);
this.parameter = parameter;
/* GRECLIPSE edit -- GROOVY-10651
this.parameter.getNodeMetaData(INFERRED_TYPE, x -> parameter.getOriginType());
this.parameter.getNodeMetaData(INFERRED_TYPE, x -> parameter.getType());
*/
ClassNode inferredType = getNodeMetaData(INFERRED_TYPE);
if (inferredType == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -668,7 +668,7 @@ public void visitVariableExpression(final VariableExpression vexp) {

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);
}
}
Expand Down Expand Up @@ -933,21 +933,27 @@ private void validateResourceInARM(final BinaryExpression expression, final Clas
}

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);

inferParameterAndReturnTypesOfClosureOnRHS(target, lambdaExpression);
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));
}
}
}

Expand All @@ -956,13 +962,17 @@ private void inferParameterAndReturnTypesOfClosureOnRHS(final ClassNode lhsType,
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);
}
Expand Down

0 comments on commit 04b56fd

Please sign in to comment.