Skip to content

Commit eda2958

Browse files
committed
GROOVY-9881
1 parent 89341d0 commit eda2958

File tree

7 files changed

+167
-5
lines changed

7 files changed

+167
-5
lines changed

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

+75
Original file line numberDiff line numberDiff line change
@@ -5435,6 +5435,81 @@ public void testCompileStatic9872() {
54355435
runConformTest(sources, "[kv:kv]");
54365436
}
54375437

5438+
@Test
5439+
public void testCompileStatic9881() {
5440+
if (Float.parseFloat(System.getProperty("java.specification.version")) > 8)
5441+
vmArguments = new String[] {"--add-opens", "java.base/java.util.function=ALL-UNNAMED"};
5442+
5443+
//@formatter:off
5444+
String[] sources = {
5445+
"Main.groovy",
5446+
"@groovy.transform.CompileStatic\n" +
5447+
"void test() {\n" +
5448+
" print new Value(123).replace { -> 'foo' }\n" +
5449+
" print new Value(123).replace { Integer v -> 'bar' }\n" +
5450+
"}\n" +
5451+
"test()\n",
5452+
5453+
"Value.groovy",
5454+
"import java.util.function.*\n" +
5455+
"class Value<V> {\n" +
5456+
" final V val\n" +
5457+
" Value(V v) {\n" +
5458+
" this.val = v\n" +
5459+
" }\n" +
5460+
" String toString() {\n" +
5461+
" val as String\n" +
5462+
" }\n" +
5463+
" def <T> Value<T> replace(Supplier<T> supplier) {\n" +
5464+
" new Value<>(supplier.get())\n" +
5465+
" }\n" +
5466+
" def <T> Value<T> replace(Function<? super V, ? extends T> function) {\n" +
5467+
" new Value(function.apply(val))\n" +
5468+
" }\n" +
5469+
"}\n",
5470+
};
5471+
//@formatter:on
5472+
5473+
runConformTest(sources, "foobar");
5474+
}
5475+
5476+
@Test
5477+
public void testCompileStatic9881a() {
5478+
assumeTrue(isParrotParser());
5479+
5480+
//@formatter:off
5481+
String[] sources = {
5482+
"Main.groovy",
5483+
"@groovy.transform.CompileStatic\n" +
5484+
"void test() {\n" +
5485+
" print new Value(123).replace(() -> 'foo')\n" +
5486+
" print new Value(123).replace((Integer v) -> 'bar')\n" +
5487+
"}\n" +
5488+
"test()\n",
5489+
5490+
"Value.groovy",
5491+
"import java.util.function.*\n" +
5492+
"class Value<V> {\n" +
5493+
" final V val\n" +
5494+
" Value(V v) {\n" +
5495+
" this.val = v\n" +
5496+
" }\n" +
5497+
" String toString() {\n" +
5498+
" val as String\n" +
5499+
" }\n" +
5500+
" def <T> Value<T> replace(Supplier<T> supplier) {\n" +
5501+
" new Value<>(supplier.get())\n" +
5502+
" }\n" +
5503+
" def <T> Value<T> replace(Function<? super V, ? extends T> function) {\n" +
5504+
" new Value(function.apply(val))\n" +
5505+
" }\n" +
5506+
"}\n",
5507+
};
5508+
//@formatter:on
5509+
5510+
runConformTest(sources, "foobar");
5511+
}
5512+
54385513
@Test
54395514
public void testCompileStatic9882() {
54405515
//@formatter:off

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

+16-1
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@
9999
import static org.codehaus.groovy.ast.ClassHelper.byte_TYPE;
100100
import static org.codehaus.groovy.ast.ClassHelper.char_TYPE;
101101
import static org.codehaus.groovy.ast.ClassHelper.double_TYPE;
102+
import static org.codehaus.groovy.ast.ClassHelper.findSAM;
102103
import static org.codehaus.groovy.ast.ClassHelper.float_TYPE;
103104
import static org.codehaus.groovy.ast.ClassHelper.getUnwrapper;
104105
import static org.codehaus.groovy.ast.ClassHelper.getWrapper;
@@ -961,16 +962,30 @@ && isPrimitiveType(unwrapCompare)
961962
if (receiver == UNKNOWN_PARAMETER_TYPE) {
962963
return dist;
963964
}
965+
// GRECLIPSE add -- GROOVY-9852, GROOVY-9881
966+
if (compare.isInterface()) { MethodNode sam;
967+
if (receiver.implementsInterface(compare)) {
968+
return dist + getMaximumInterfaceDistance(receiver, compare);
969+
} else if (receiver.equals(CLOSURE_TYPE) && (sam = findSAM(compare)) != null) {
970+
// GROOVY-9881: in case of multiple overloads, give preference to equal parameter count
971+
Integer closureParamCount = receiver.getNodeMetaData(StaticTypesMarker.CLOSURE_ARGUMENTS);
972+
if (closureParamCount != null && closureParamCount == sam.getParameters().length) dist -= 1;
964973

965-
ClassNode ref = isPrimitiveType(receiver) && !isPrimitiveType(compare) ? ClassHelper.getWrapper(receiver) : receiver;
974+
return dist + 13; // GROOVY-9852: @FunctionalInterface vs Object
975+
}
976+
}
977+
// GRECLIPSE end
978+
ClassNode ref = isPrimitiveType(receiver) && !isPrimitiveType(compare) ? getWrapper(receiver) : receiver;
966979
while (ref != null) {
980+
/* GRECLIPSE edit
967981
if (compare.equals(ref)) {
968982
break;
969983
}
970984
if (compare.isInterface() && ref.implementsInterface(compare)) {
971985
dist += getMaximumInterfaceDistance(ref, compare);
972986
break;
973987
}
988+
*/
974989
ref = ref.getSuperClass();
975990
dist++;
976991
if (ref == null) dist++;

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

+14
Original file line numberDiff line numberDiff line change
@@ -5256,13 +5256,27 @@ protected ClassNode getType(final ASTNode exp) {
52565256
return ((Parameter) exp).getOriginType();
52575257
}
52585258
if (exp instanceof ClosureExpression) {
5259+
/* GRECLIPSE edit -- GROOVY-9881
52595260
ClassNode irt = getInferredReturnType(exp);
52605261
if (irt != null) {
52615262
irt = wrapTypeIfNecessary(irt);
52625263
ClassNode result = CLOSURE_TYPE.getPlainNodeReference();
52635264
result.setGenericsTypes(new GenericsType[]{new GenericsType(irt)});
52645265
return result;
52655266
}
5267+
*/
5268+
ClassNode type = CLOSURE_TYPE.getPlainNodeReference();
5269+
ClassNode returnType = getInferredReturnType(exp);
5270+
if (returnType != null) {
5271+
type.setGenericsTypes(new GenericsType[]{
5272+
new GenericsType(wrapTypeIfNecessary(returnType))
5273+
});
5274+
}
5275+
Parameter[] parameters = ((ClosureExpression) exp).getParameters();
5276+
int nParameters = parameters == null ? 0 : parameters.length == 0 ? -1 : parameters.length;
5277+
type.putNodeMetaData(StaticTypesMarker.CLOSURE_ARGUMENTS, nParameters);
5278+
return type;
5279+
// GRECLIPSE end
52665280
} else if (exp instanceof MethodCall) {
52675281
MethodNode target = (MethodNode) exp.getNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET);
52685282
if (target != null) {

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

+16-2
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020

2121
import org.apache.groovy.util.Maps;
2222
import org.codehaus.groovy.GroovyBugError;
23-
import org.codehaus.groovy.ast.ClassHelper;
2423
import org.codehaus.groovy.ast.ClassNode;
2524
import org.codehaus.groovy.ast.GenericsType;
2625
import org.codehaus.groovy.ast.GenericsType.GenericsTypeName;
@@ -93,6 +92,7 @@
9392
import static org.codehaus.groovy.ast.ClassHelper.byte_TYPE;
9493
import static org.codehaus.groovy.ast.ClassHelper.char_TYPE;
9594
import static org.codehaus.groovy.ast.ClassHelper.double_TYPE;
95+
import static org.codehaus.groovy.ast.ClassHelper.findSAM;
9696
import static org.codehaus.groovy.ast.ClassHelper.float_TYPE;
9797
import static org.codehaus.groovy.ast.ClassHelper.getUnwrapper;
9898
import static org.codehaus.groovy.ast.ClassHelper.getWrapper;
@@ -913,16 +913,30 @@ && isPrimitiveType(unwrapCompare)
913913
if (receiver == UNKNOWN_PARAMETER_TYPE) {
914914
return dist;
915915
}
916+
// GRECLIPSE add -- GROOVY-9852, GROOVY-9881
917+
if (compare.isInterface()) { MethodNode sam;
918+
if (receiver.implementsInterface(compare)) {
919+
return dist + getMaximumInterfaceDistance(receiver, compare);
920+
} else if (receiver.equals(CLOSURE_TYPE) && (sam = findSAM(compare)) != null) {
921+
// GROOVY-9881: in case of multiple overloads, give preference to equal parameter count
922+
Integer closureParamCount = receiver.getNodeMetaData(StaticTypesMarker.CLOSURE_ARGUMENTS);
923+
if (closureParamCount != null && closureParamCount == sam.getParameters().length) dist -= 1;
916924

917-
ClassNode ref = isPrimitiveType(receiver) && !isPrimitiveType(compare) ? ClassHelper.getWrapper(receiver) : receiver;
925+
return dist + 13; // GROOVY-9852: @FunctionalInterface vs Object
926+
}
927+
}
928+
// GRECLIPSE end
929+
ClassNode ref = isPrimitiveType(receiver) && !isPrimitiveType(compare) ? getWrapper(receiver) : receiver;
918930
while (ref != null) {
931+
/* GRECLIPSE edit
919932
if (compare.equals(ref)) {
920933
break;
921934
}
922935
if (compare.isInterface() && ref.implementsInterface(compare)) {
923936
dist += getMaximumInterfaceDistance(ref, compare);
924937
break;
925938
}
939+
*/
926940
ref = ref.getSuperClass();
927941
dist += 1;
928942
if (OBJECT_TYPE.equals(ref))

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

+15
Original file line numberDiff line numberDiff line change
@@ -4989,13 +4989,28 @@ protected ClassNode getType(final ASTNode exp) {
49894989
return ((Parameter) exp).getOriginType();
49904990
}
49914991
if (exp instanceof ClosureExpression) {
4992+
/* GRECLIPSE edit -- GROOVY-9881
49924993
ClassNode irt = getInferredReturnType(exp);
49934994
if (irt != null) {
49944995
irt = wrapTypeIfNecessary(irt);
49954996
ClassNode result = CLOSURE_TYPE.getPlainNodeReference();
49964997
result.setGenericsTypes(new GenericsType[]{new GenericsType(irt)});
49974998
return result;
49984999
}
5000+
*/
5001+
ClassNode type = CLOSURE_TYPE.getPlainNodeReference();
5002+
ClassNode returnType = getInferredReturnType(exp);
5003+
if (returnType != null) {
5004+
type.setGenericsTypes(new GenericsType[]{
5005+
new GenericsType(wrapTypeIfNecessary(returnType))
5006+
});
5007+
}
5008+
Parameter[] parameters = ((ClosureExpression) exp).getParameters();
5009+
int nParameters = parameters == null ? 0
5010+
: parameters.length == 0 ? -1 : parameters.length;
5011+
type.putNodeMetaData(CLOSURE_ARGUMENTS, nParameters);
5012+
return type;
5013+
// GRECLIPSE end
49995014
} else if (exp instanceof MethodCall) {
50005015
MethodNode target = exp.getNodeMetaData(DIRECT_METHOD_CALL_TARGET);
50015016
if (target != null) {

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

+16-2
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020

2121
import org.apache.groovy.util.Maps;
2222
import org.codehaus.groovy.GroovyBugError;
23-
import org.codehaus.groovy.ast.ClassHelper;
2423
import org.codehaus.groovy.ast.ClassNode;
2524
import org.codehaus.groovy.ast.GenericsType;
2625
import org.codehaus.groovy.ast.GenericsType.GenericsTypeName;
@@ -93,6 +92,7 @@
9392
import static org.codehaus.groovy.ast.ClassHelper.byte_TYPE;
9493
import static org.codehaus.groovy.ast.ClassHelper.char_TYPE;
9594
import static org.codehaus.groovy.ast.ClassHelper.double_TYPE;
95+
import static org.codehaus.groovy.ast.ClassHelper.findSAM;
9696
import static org.codehaus.groovy.ast.ClassHelper.float_TYPE;
9797
import static org.codehaus.groovy.ast.ClassHelper.getUnwrapper;
9898
import static org.codehaus.groovy.ast.ClassHelper.getWrapper;
@@ -912,16 +912,30 @@ && isPrimitiveType(unwrapCompare)
912912
if (receiver == UNKNOWN_PARAMETER_TYPE) {
913913
return dist;
914914
}
915+
// GRECLIPSE add -- GROOVY-9852, GROOVY-9881
916+
if (compare.isInterface()) { MethodNode sam;
917+
if (receiver.implementsInterface(compare)) {
918+
return dist + getMaximumInterfaceDistance(receiver, compare);
919+
} else if (receiver.equals(CLOSURE_TYPE) && (sam = findSAM(compare)) != null) {
920+
// GROOVY-9881: in case of multiple overloads, give preference to equal parameter count
921+
Integer closureParamCount = receiver.getNodeMetaData(StaticTypesMarker.CLOSURE_ARGUMENTS);
922+
if (closureParamCount != null && closureParamCount == sam.getParameters().length) dist -= 1;
915923

916-
ClassNode ref = isPrimitiveType(receiver) && !isPrimitiveType(compare) ? ClassHelper.getWrapper(receiver) : receiver;
924+
return dist + 13; // GROOVY-9852: @FunctionalInterface vs Object
925+
}
926+
}
927+
// GRECLIPSE end
928+
ClassNode ref = isPrimitiveType(receiver) && !isPrimitiveType(compare) ? getWrapper(receiver) : receiver;
917929
while (ref != null) {
930+
/* GRECLIPSE edit
918931
if (compare.equals(ref)) {
919932
break;
920933
}
921934
if (compare.isInterface() && ref.implementsInterface(compare)) {
922935
dist += getMaximumInterfaceDistance(ref, compare);
923936
break;
924937
}
938+
*/
925939
ref = ref.getSuperClass();
926940
dist += 1;
927941
if (OBJECT_TYPE.equals(ref))

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

+15
Original file line numberDiff line numberDiff line change
@@ -4955,13 +4955,28 @@ protected ClassNode getType(final ASTNode exp) {
49554955
return ((Parameter) exp).getOriginType();
49564956
}
49574957
if (exp instanceof ClosureExpression) {
4958+
/* GRECLIPSE edit -- GROOVY-9881
49584959
ClassNode irt = getInferredReturnType(exp);
49594960
if (irt != null) {
49604961
irt = wrapTypeIfNecessary(irt);
49614962
ClassNode result = CLOSURE_TYPE.getPlainNodeReference();
49624963
result.setGenericsTypes(new GenericsType[]{new GenericsType(irt)});
49634964
return result;
49644965
}
4966+
*/
4967+
ClassNode type = CLOSURE_TYPE.getPlainNodeReference();
4968+
ClassNode returnType = getInferredReturnType(exp);
4969+
if (returnType != null) {
4970+
type.setGenericsTypes(new GenericsType[]{
4971+
new GenericsType(wrapTypeIfNecessary(returnType))
4972+
});
4973+
}
4974+
Parameter[] parameters = ((ClosureExpression) exp).getParameters();
4975+
int nParameters = parameters == null ? 0
4976+
: parameters.length == 0 ? -1 : parameters.length;
4977+
type.putNodeMetaData(CLOSURE_ARGUMENTS, nParameters);
4978+
return type;
4979+
// GRECLIPSE end
49654980
} else if (exp instanceof MethodCall) {
49664981
MethodNode target = exp.getNodeMetaData(DIRECT_METHOD_CALL_TARGET);
49674982
if (target != null) {

0 commit comments

Comments
 (0)