Skip to content

Commit 0d5285f

Browse files
committed
GROOVY-10277
1 parent 07d8466 commit 0d5285f

File tree

5 files changed

+190
-179
lines changed

5 files changed

+190
-179
lines changed

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

+4-5
Original file line numberDiff line numberDiff line change
@@ -5998,11 +5998,10 @@ public void testCompileStatic9883() {
59985998

59995999
runNegativeTest(sources,
60006000
"----------\n" +
6001-
"1. ERROR in Main.groovy (at line 3)\n" +
6002-
"\tjava.util.function.Supplier<String> p = {\n" +
6003-
"\t ^\n" +
6004-
"Groovy:[Static type checking] - Incompatible generic argument types. " +
6005-
"Cannot assign java.util.function.Supplier<java.util.UUID> to: java.util.function.Supplier<java.lang.String>\n" +
6001+
"1. ERROR in Main.groovy (at line 4)\n" +
6002+
"\treturn java.util.UUID.randomUUID()\n" +
6003+
"\t ^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" +
6004+
"Groovy:[Static type checking] - Cannot return value of type java.util.UUID for closure expecting java.lang.String\n" +
60066005
"----------\n");
60076006
}
60086007

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

+49-24
Original file line numberDiff line numberDiff line change
@@ -1026,7 +1026,7 @@ public void testTypeChecked7316() {
10261026
"1. ERROR in Main.groovy (at line 11)\n" +
10271027
"\tseq()\n" +
10281028
"\t^^^^^\n" +
1029-
"Groovy:[Static type checking] - Cannot return value of type #T on method returning type java.util.List<?>\n" +
1029+
"Groovy:[Static type checking] - Cannot return value of type #T for method returning java.util.List<?>\n" +
10301030
"----------\n");
10311031
}
10321032

@@ -3538,27 +3538,6 @@ public void testTypeChecked10082() {
35383538
runConformTest(sources, "truetrue");
35393539
}
35403540

3541-
@Test
3542-
public void testTypeChecked10082a() {
3543-
//@formatter:off
3544-
String[] sources = {
3545-
"Main.groovy",
3546-
"@groovy.transform.TypeChecked\n" +
3547-
"void test() {\n" +
3548-
" Closure<String> c = {-> 42}\n" +
3549-
"}\n",
3550-
};
3551-
//@formatter:on
3552-
3553-
runNegativeTest(sources,
3554-
"----------\n" +
3555-
"1. ERROR in Main.groovy (at line 3)\n" +
3556-
"\tClosure<String> c = {-> 42}\n" +
3557-
"\t ^^^^^^^\n" +
3558-
"Groovy:[Static type checking] - Incompatible generic argument types. Cannot assign groovy.lang.Closure<java.lang.Integer> to: groovy.lang.Closure<java.lang.String>\n" +
3559-
"----------\n");
3560-
}
3561-
35623541
@Test
35633542
public void testTypeChecked10086() {
35643543
//@formatter:off
@@ -3664,8 +3643,8 @@ public void testTypeChecked10091() {
36643643
"----------\n" +
36653644
"1. ERROR in Main.groovy (at line 8)\n" +
36663645
"\tClosure<A<Number>> x = { -> new X()}\n" +
3667-
"\t ^^^^^^^^^^^^^\n" +
3668-
"Groovy:[Static type checking] - Incompatible generic argument types. Cannot assign groovy.lang.Closure<X> to: groovy.lang.Closure<A<java.lang.Number>>\n" +
3646+
"\t ^^^^^^^\n" +
3647+
"Groovy:[Static type checking] - Cannot return value of type X for closure expecting A<java.lang.Number>\n" +
36693648
"----------\n");
36703649
}
36713650

@@ -4202,6 +4181,52 @@ public void testTypeChecked10269() {
42024181
"----------\n");
42034182
}
42044183

4184+
@Test
4185+
public void testTypeChecked10277() {
4186+
//@formatter:off
4187+
String[] sources = {
4188+
"Main.groovy",
4189+
"import java.util.function.*\n" +
4190+
"Long foo(Closure<Long> c) {\n" +
4191+
" c()\n" +
4192+
"}\n" +
4193+
"Long bar(Supplier<Long> s) {\n" +
4194+
" s.get()\n" +
4195+
"}\n" +
4196+
"@groovy.transform.TypeChecked\n" +
4197+
"void test() {\n" +
4198+
" foo { -> false}\n" +
4199+
" bar { -> false};\n" +
4200+
" (Supplier<Long>) { -> false};\n" +
4201+
" { -> false} as Supplier<Long>\n" +
4202+
"}\n",
4203+
};
4204+
//@formatter:on
4205+
4206+
runNegativeTest(sources,
4207+
"----------\n" +
4208+
"1. ERROR in Main.groovy (at line 10)\n" +
4209+
"\tfoo { -> false}\n" +
4210+
"\t ^^^^^\n" +
4211+
"Groovy:[Static type checking] - Cannot return value of type boolean for closure expecting java.lang.Long\n" +
4212+
"----------\n" +
4213+
"2. ERROR in Main.groovy (at line 11)\n" +
4214+
"\tbar { -> false};\n" +
4215+
"\t ^^^^^\n" +
4216+
"Groovy:[Static type checking] - Cannot return value of type boolean for closure expecting java.lang.Long\n" +
4217+
"----------\n" +
4218+
"3. ERROR in Main.groovy (at line 12)\n" +
4219+
"\t(Supplier<Long>) { -> false};\n" +
4220+
"\t ^^^^^\n" +
4221+
"Groovy:[Static type checking] - Cannot return value of type boolean for closure expecting java.lang.Long\n" +
4222+
"----------\n" +
4223+
"4. ERROR in Main.groovy (at line 13)\n" +
4224+
"\t{ -> false} as Supplier<Long>\n" +
4225+
"\t ^^^^^\n" +
4226+
"Groovy:[Static type checking] - Cannot return value of type boolean for closure expecting java.lang.Long\n" +
4227+
"----------\n");
4228+
}
4229+
42054230
@Test
42064231
public void testTypeChecked10280() {
42074232
//@formatter:off

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

+23-13
Original file line numberDiff line numberDiff line change
@@ -1529,7 +1529,9 @@ private void checkTypeGenerics(ClassNode leftExpressionType, ClassNode wrappedRH
15291529
// List<Foo> l = new List() is an example for incomplete generics type info
15301530
// we assume arity related errors are already handled here.
15311531
if (hasRHSIncompleteGenericTypeInfo(wrappedRHS)) return;
1532-
1532+
// GRECLIPSE add -- GROOVY-10277
1533+
if (rightExpression instanceof ClosureExpression) return;
1534+
// GRECLIPSE end
15331535
GenericsType gt = GenericsUtils.buildWildcardType(leftExpressionType);
15341536
if (UNKNOWN_PARAMETER_TYPE.equals(wrappedRHS) ||
15351537
gt.isCompatibleWith(wrappedRHS) ||
@@ -2753,9 +2755,8 @@ private ClassNode infer(ClassNode target, ClassNode source) {
27532755

27542756
protected ClassNode checkReturnType(final ReturnStatement statement) {
27552757
Expression expression = statement.getExpression();
2756-
/* GRECLIPSE edit -- GROOVY-8310, GROOVY-9907, GROOVY-9971, GROOVY-9995, GROOVY-10080, GROOVY-10082, GROOVY-10091
27572758
ClassNode type = getType(expression);
2758-
2759+
/* GRECLIPSE edit -- GROOVY-8310, GROOVY-9907, GROOVY-9971, GROOVY-9995, GROOVY-10080, GROOVY-10082, GROOVY-10091, GROOVY-10277
27592760
if (typeCheckingContext.getEnclosingClosure() != null) {
27602761
return type;
27612762
}
@@ -2764,17 +2765,25 @@ protected ClassNode checkReturnType(final ReturnStatement statement) {
27642765
type = expression.getNodeMetaData(StaticTypesMarker.INFERRED_RETURN_TYPE);
27652766
}
27662767
*/
2767-
ClassNode type = getType(expression);
2768-
if (typeCheckingContext.getEnclosingClosure() != null) {
2769-
ClassNode inferredReturnType = getInferredReturnType(typeCheckingContext.getEnclosingClosure().getClosureExpression());
2768+
TypeCheckingContext.EnclosingClosure enclosingClosure = typeCheckingContext.getEnclosingClosure();
2769+
if (enclosingClosure != null) { if (enclosingClosure.getClosureExpression().getNodeMetaData(StaticTypesMarker.INFERRED_TYPE) != null) return null;
2770+
ClassNode inferredReturnType = getInferredReturnType(enclosingClosure.getClosureExpression());
27702771
if (expression instanceof ConstructorCallExpression) {
27712772
inferDiamondType((ConstructorCallExpression) expression, inferredReturnType != null ? inferredReturnType : DYNAMIC_TYPE);
27722773
}
2773-
if (STRING_TYPE.equals(inferredReturnType) && StaticTypeCheckingSupport.isGStringOrGStringStringLUB(type)) {
2774-
type = STRING_TYPE; // implicit "toString()" before return
2775-
} else if (inferredReturnType != null && !GenericsUtils.hasUnresolvedGenerics(inferredReturnType)
2776-
&& GenericsUtils.buildWildcardType(inferredReturnType).isCompatibleWith(wrapTypeIfNecessary(type))) {
2777-
type = inferredReturnType; // allow simple covariance
2774+
if (inferredReturnType != null
2775+
&& !inferredReturnType.equals(type)
2776+
&& !inferredReturnType.equals(VOID_TYPE)
2777+
&& !inferredReturnType.equals(OBJECT_TYPE)
2778+
&& !inferredReturnType.equals(boolean_TYPE)
2779+
&& !GenericsUtils.hasUnresolvedGenerics(inferredReturnType)) {
2780+
if (inferredReturnType.equals(STRING_TYPE) && StaticTypeCheckingSupport.isGStringOrGStringStringLUB(type)) {
2781+
type = STRING_TYPE; // implicit "toString()" before return
2782+
} else if (GenericsUtils.buildWildcardType(wrapTypeIfNecessary(inferredReturnType)).isCompatibleWith(wrapTypeIfNecessary(type))) {
2783+
type = inferredReturnType; // allow simple covariance
2784+
} else if (!type.equals(VOID_TYPE) && !extension.handleIncompatibleReturnType(statement, type)) {
2785+
addStaticTypeError("Cannot return value of type " + prettyPrintType(type) + " for closure expecting " + prettyPrintType(inferredReturnType), expression);
2786+
}
27782787
}
27792788
return type;
27802789
}
@@ -2787,7 +2796,7 @@ protected ClassNode checkReturnType(final ReturnStatement statement) {
27872796
&& !type.equals(void_WRAPPER_TYPE)
27882797
&& !checkCompatibleAssignmentTypes(returnType, type, null, false)) {
27892798
if (!extension.handleIncompatibleReturnType(statement, type)) {
2790-
addStaticTypeError("Cannot return value of type " + prettyPrintType(type) + " on method returning type " + prettyPrintType(returnType), expression);
2799+
addStaticTypeError("Cannot return value of type " + prettyPrintType(type) + " for method returning " + prettyPrintType(returnType), expression);
27912800
}
27922801
} else {
27932802
/* GRECLIPSE edit -- GROOVY-10295
@@ -4411,12 +4420,13 @@ && isNumberType(getType(argumentList.getExpression(0)))) {
44114420
for (int i = 0, n = Math.min(arguments.size(), parameters.length); i < n; i += 1) {
44124421
Expression argument = arguments.get(i); ClassNode aType = getType(argument), pType = parameters[i].getType();
44134422
if (CLOSURE_TYPE.equals(pType) && CLOSURE_TYPE.equals(aType)) {
4414-
// GROOVY-8310
4423+
/* GRECLIPSE edit -- GROOVY-8310, GROOVY-10277
44154424
if (!name.equals("collectMany") && pType.isUsingGenerics() && !GenericsUtils.buildWildcardType(pType).isCompatibleWith(aType)) {
44164425
addNoMatchingMethodError(receiver, name, getArgumentTypes(argumentList), call);
44174426
call.removeNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET);
44184427
break;
44194428
}
4429+
*/
44204430
// GROOVY-7996
44214431
if (argument instanceof VariableExpression && ((VariableExpression) argument).getAccessedVariable() instanceof Parameter) {
44224432
int incomingStrategy = getResolveStrategy((Parameter) ((VariableExpression) argument).getAccessedVariable()), outgoingStrategy = getResolveStrategy(parameters[i]);

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

+22-8
Original file line numberDiff line numberDiff line change
@@ -1450,7 +1450,9 @@ private void checkTypeGenerics(final ClassNode leftExpressionType, final ClassNo
14501450
// List<Foo> l = new List() is an example for incomplete generics type info
14511451
// we assume arity related errors are already handled here.
14521452
if (hasRHSIncompleteGenericTypeInfo(wrappedRHS)) return;
1453-
1453+
// GRECLIPSE add -- GROOVY-10277
1454+
if (rightExpression instanceof ClosureExpression) return;
1455+
// GRECLIPSE end
14541456
GenericsType gt = GenericsUtils.buildWildcardType(leftExpressionType);
14551457
if (UNKNOWN_PARAMETER_TYPE.equals(wrappedRHS) ||
14561458
gt.isCompatibleWith(wrappedRHS) ||
@@ -2501,19 +2503,30 @@ protected ClassNode checkReturnType(final ReturnStatement statement) {
25012503
type = getType(expression);
25022504
}
25032505
if (typeCheckingContext.getEnclosingClosure() != null) {
2506+
// GRECLIPSE add
2507+
if (typeCheckingContext.getEnclosingClosure().getClosureExpression().getNodeMetaData(INFERRED_TYPE) != null) return null;
2508+
// GRECLIPSE end
25042509
ClassNode inferredReturnType = getInferredReturnType(typeCheckingContext.getEnclosingClosure().getClosureExpression());
2505-
// GRECLIPSE add -- GROOVY-8310, GROOVY-9995, GROOVY-10080, GROOVY-10082, GROOVY-10091
2510+
// GRECLIPSE add -- GROOVY-8310, GROOVY-9995, GROOVY-10080, GROOVY-10082, GROOVY-10091, GROOVY-10277
25062511
if (expression instanceof ConstructorCallExpression) {
25072512
inferDiamondType((ConstructorCallExpression) expression, inferredReturnType != null ? inferredReturnType : DYNAMIC_TYPE);
25082513
}
2514+
if (inferredReturnType != null
2515+
&& !inferredReturnType.equals(type)
2516+
&& !inferredReturnType.equals(VOID_TYPE)
2517+
&& !inferredReturnType.equals(OBJECT_TYPE)
2518+
&& !inferredReturnType.equals(boolean_TYPE)
2519+
&& !GenericsUtils.hasUnresolvedGenerics(inferredReturnType))
25092520
// GRECLIPSE end
2510-
if (inferredReturnType != null && inferredReturnType.equals(STRING_TYPE) && isGStringOrGStringStringLUB(type)) {
2521+
if (inferredReturnType.equals(STRING_TYPE) && isGStringOrGStringStringLUB(type)) {
25112522
type = STRING_TYPE; // GROOVY-9971: convert GString to String at point of return
25122523
}
25132524
// GRECLIPSE add
2514-
else if (inferredReturnType != null && !GenericsUtils.hasUnresolvedGenerics(inferredReturnType)
2515-
&& GenericsUtils.buildWildcardType(inferredReturnType).isCompatibleWith(wrapTypeIfNecessary(type))) {
2525+
else if (GenericsUtils.buildWildcardType(wrapTypeIfNecessary(inferredReturnType)).isCompatibleWith(wrapTypeIfNecessary(type))) {
25162526
type = inferredReturnType; // allow simple covariance
2527+
} else if (!type.equals(VOID_TYPE) && !extension.handleIncompatibleReturnType(statement, type)) {
2528+
String kind = typeCheckingContext.getEnclosingClosure().getClosureExpression() instanceof LambdaExpression ? "lambda" : "closure";
2529+
addStaticTypeError("Cannot return value of type " + prettyPrintType(type) + " for " + kind + " expecting " + prettyPrintType(inferredReturnType), expression);
25172530
}
25182531
// GRECLIPSE end
25192532
return type;
@@ -2526,7 +2539,7 @@ else if (inferredReturnType != null && !GenericsUtils.hasUnresolvedGenerics(infe
25262539
&& !type.equals(void_WRAPPER_TYPE)
25272540
&& !checkCompatibleAssignmentTypes(returnType, type, null, false)) {
25282541
if (!extension.handleIncompatibleReturnType(statement, type)) {
2529-
addStaticTypeError("Cannot return value of type " + prettyPrintType(type) + " on method returning type " + prettyPrintType(returnType), expression);
2542+
addStaticTypeError("Cannot return value of type " + prettyPrintType(type) + " for method returning " + prettyPrintType(returnType), expression);
25302543
}
25312544
} else {
25322545
/* GRECLIPSE edit -- GROOVY-10295
@@ -4033,12 +4046,13 @@ && isNumberType(getType(argumentList.getExpression(0)))) {
40334046
Expression argument = arguments.get(i);
40344047
ClassNode aType = getType(argument), pType = parameters[i].getType();
40354048
if (CLOSURE_TYPE.equals(aType) && CLOSURE_TYPE.equals(pType)) {
4036-
// GROOVY-8310: check closure generics
4037-
if (!isAssignableTo(aType, pType) /*&& !extension.handleIncompatibleReturnType(getReturnStatement(argument), aType)*/) {
4049+
/* GRECLIPSE edit -- GROOVY-8310, GROOVY-10277
4050+
if (!isAssignableTo(aType, pType) && !extension.handleIncompatibleReturnType(getReturnStatement(argument), aType)) {
40384051
addNoMatchingMethodError(receiver, name, getArgumentTypes(argumentList), call);
40394052
call.removeNodeMetaData(DIRECT_METHOD_CALL_TARGET);
40404053
break;
40414054
}
4055+
*/
40424056
// GROOVY-7996: check delegation metadata of closure parameter used as method call argument
40434057
if (argument instanceof VariableExpression && ((VariableExpression) argument).getAccessedVariable() instanceof Parameter) {
40444058
// TODO: Check additional delegation metadata like type (see checkClosureWithDelegatesTo).

0 commit comments

Comments
 (0)