Skip to content

Commit 39e19d5

Browse files
committed
GROOVY-10229 (pt.2), GROOVY-10339 (pt.2), GROOVY-10347 (pt.2)
1 parent 54e560a commit 39e19d5

File tree

11 files changed

+167
-88
lines changed

11 files changed

+167
-88
lines changed

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

+72-2
Original file line numberDiff line numberDiff line change
@@ -4066,6 +4066,28 @@ public void testCompileStatic9127() {
40664066
runConformTest(sources, "bar");
40674067
}
40684068

4069+
@Test
4070+
public void testCompileStatic9132() {
4071+
assumeTrue(isParrotParser());
4072+
4073+
//@formatter:off
4074+
String[] sources = {
4075+
"Main.groovy",
4076+
"import java.util.function.Function\n" +
4077+
"def <R> R transform(Function<? super String, ? extends R> f) {\n" +
4078+
" f.apply('foo')\n" +
4079+
"}\n" +
4080+
"@groovy.transform.CompileStatic\n" +
4081+
"void test() {\n" +
4082+
" print(transform(String::length) * 3)\n" +
4083+
"}\n" +
4084+
"test()\n",
4085+
};
4086+
//@formatter:on
4087+
4088+
runConformTest(sources, "9");
4089+
}
4090+
40694091
@Test
40704092
public void testCompileStatic9136() {
40714093
//@formatter:off
@@ -5756,6 +5778,26 @@ public void testCompileStatic9799() {
57565778
runConformTest(sources, "works");
57575779
}
57585780

5781+
@Test(expected = AssertionError.class) // see GROOVY-10047
5782+
public void testCompileStatic9853() {
5783+
assumeTrue(isParrotParser());
5784+
5785+
//@formatter:off
5786+
String[] sources = {
5787+
"Main.groovy",
5788+
"import static java.util.stream.Collectors.toMap\n" +
5789+
"import java.util.function.Function\n" +
5790+
"@groovy.transform.CompileStatic\n" +
5791+
"void test() {\n" +
5792+
" print(['a','bc','def'].stream().collect(toMap(Function.<String>identity(), CharSequence::length)))\n" +
5793+
"}\n" + // <T,K,U> Collector<T,?,Map<K,U>> toMap(Function<? super T,? extends K>,Function<? super T,? extends U>)
5794+
"test()\n",
5795+
};
5796+
//@formatter:on
5797+
5798+
runConformTest(sources, "[a:1, bc:2, def:3]");
5799+
}
5800+
57595801
@Test
57605802
public void testCompileStatic9855() {
57615803
//@formatter:off
@@ -6328,20 +6370,48 @@ public void testCompileStatic10033a() {
63286370
public void testCompileStatic10047() {
63296371
assumeTrue(isParrotParser());
63306372

6373+
for (String value : new String[] {"String::length", "String.&length", "s -> s.length()", "{s -> s.length()}"}) {
6374+
//@formatter:off
6375+
String[] sources = {
6376+
"Main.groovy",
6377+
"import static java.util.stream.Collectors.toMap\n" +
6378+
"import java.util.function.Function\n" +
6379+
"@groovy.transform.CompileStatic\n" +
6380+
"void test() {\n" +
6381+
" print(['a','bc','def'].stream().collect(toMap(Function.<String>identity(), " + value + ")))\n" +
6382+
"}\n" + // <T,K,U> Collector<T,?,Map<K,U>> toMap(Function<? super T,? extends K>,Function<? super T,? extends U>)
6383+
"test()\n",
6384+
};
6385+
//@formatter:on
6386+
6387+
runConformTest(sources, "[a:1, bc:2, def:3]");
6388+
}
6389+
}
6390+
6391+
@Test
6392+
public void testCompileStatic10047x() {
6393+
assumeTrue(isParrotParser());
6394+
63316395
//@formatter:off
63326396
String[] sources = {
63336397
"Main.groovy",
63346398
"import static java.util.stream.Collectors.toMap\n" +
63356399
"import java.util.function.Function\n" +
63366400
"@groovy.transform.CompileStatic\n" +
63376401
"void test() {\n" +
6338-
" print(['a','bc','def'].stream().collect(toMap(Function.<String>identity(), String::length)))\n" +
6402+
" print(['a','bc','def'].stream().collect(toMap(Function.<String>identity(), List::size)))\n" +
63396403
"}\n" + // <T,K,U> Collector<T,?,Map<K,U>> toMap(Function<? super T,? extends K>,Function<? super T,? extends U>)
63406404
"test()\n",
63416405
};
63426406
//@formatter:on
63436407

6344-
runConformTest(sources, "[a:1, bc:2, def:3]");
6408+
runNegativeTest(sources,
6409+
"----------\n" +
6410+
"1. ERROR in Main.groovy (at line 5)\n" +
6411+
"\tprint(['a','bc','def'].stream().collect(toMap(Function.<String>identity(), List::size)))\n" +
6412+
"\t ^^^^^^^^^^\n" +
6413+
"Groovy:Failed to find the expected method[size(java.lang.String)] in the type[java.util.List]\n" +
6414+
"----------\n");
63456415
}
63466416

63476417
@Test

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

+57-6
Original file line numberDiff line numberDiff line change
@@ -601,6 +601,34 @@ public void testTypeChecked6455() {
601601
runConformTest(sources);
602602
}
603603

604+
@Test
605+
public void testTypeChecked6731() {
606+
if (Float.parseFloat(System.getProperty("java.specification.version")) > 8)
607+
vmArguments = new String[] {"--add-opens", "java.base/java.util.function=ALL-UNNAMED"};
608+
609+
//@formatter:off
610+
String[] sources = {
611+
"Main.groovy",
612+
"import java.util.function.Function\n" +
613+
"def <I, O> void transform(Function<? super I, ? extends O> function) {\n" +
614+
" print(function.apply('hello'))\n" +
615+
"}\n" +
616+
"@groovy.transform.TypeChecked\n" +
617+
"void test() {\n" +
618+
" transform(new Function<String, String>() {\n" +
619+
" @Override\n" +
620+
" String apply(String input) {\n" +
621+
" input + ' world'\n" +
622+
" }\n" +
623+
" })\n" +
624+
"}\n" +
625+
"test()\n",
626+
};
627+
//@formatter:on
628+
629+
runConformTest(sources, "hello world");
630+
}
631+
604632
@Test
605633
public void testTypeChecked6786() {
606634
//@formatter:off
@@ -1499,6 +1527,33 @@ public void testTypeChecked8983c() {
14991527
runConformTest(sources, "[foo, bar]");
15001528
}
15011529

1530+
@Test
1531+
public void testTypeChecked8983d() {
1532+
//@formatter:off
1533+
String[] sources = {
1534+
"Main.groovy",
1535+
"@groovy.transform.TypeChecked\n" +
1536+
"class C {\n" +
1537+
" List<String> list = []\n" +
1538+
" void setX(String[] array) {\n" +
1539+
" Collections.addAll(list, array)\n" +
1540+
" }\n" +
1541+
"}\n" +
1542+
"List<String> m() { ['foo'] }\n" +
1543+
"@groovy.transform.TypeChecked\n" +
1544+
"void test(Set<String> set) {\n" +
1545+
" def c = new C()\n" +
1546+
" c.x = m()" + (isAtLeastGroovy(40) ? "\n" : " as String[]\n") +
1547+
" c.x = set" + (isAtLeastGroovy(40) ? "\n" : " as String[]\n") +
1548+
" print(c.list)\n" +
1549+
"}\n" +
1550+
"test(['bar'].toSet())\n",
1551+
};
1552+
//@formatter:on
1553+
1554+
runConformTest(sources, "[foo, bar]");
1555+
}
1556+
15021557
@Test
15031558
public void testTypeChecked8984() {
15041559
//@formatter:off
@@ -4663,9 +4718,7 @@ public void testTypeChecked10339() {
46634718
"1. ERROR in Main.groovy (at line 7)\n" +
46644719
"\tInteger i = bar(foo(), 1)\n" +
46654720
"\t ^^^^^^^^^^^^^\n" +
4666-
"Groovy:[Static type checking] - Cannot assign value of type " +
4667-
(isAtLeastGroovy(40) ? "java.lang.String" : "java.io.Serializable<? extends java.io.Serializable<java.lang.String>>") +
4668-
" to variable of type java.lang.Integer\n" +
4721+
"Groovy:[Static type checking] - Cannot assign value of type java.io.Serializable<? extends java.io.Serializable<java.lang.String>> to variable of type java.lang.Integer\n" +
46694722
"----------\n");
46704723
}
46714724

@@ -4714,9 +4767,7 @@ public void testTypeChecked10347a() {
47144767
"Main.groovy",
47154768
"@groovy.transform.TypeChecked\n" +
47164769
"void test(Pogo[] pogos) {\n" +
4717-
" List<String> strings = pogos.sort(true, new Sorter()).collect { Pogo pogo ->\n" + // static <T> T[] sort(T[], boolean, Comparator<? super T>)
4718-
" pogo.x\n" +
4719-
" }\n" +
4770+
" List<String> strings = pogos.sort(true, new Sorter())*.x\n" + // sort(T[],boolean,Comparator<? super T>)
47204771
" print strings\n" +
47214772
"}\n" +
47224773
"test(new Pogo(x:'foo'),new Pogo(x:'bar'))\n",

base/org.codehaus.groovy25/src/org/codehaus/groovy/ast/tools/WideningCategories.java

+4-16
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,9 @@ public static ClassNode lowestUpperBound(ClassNode a, ClassNode b) {
257257
*/
258258
private static ClassNode parameterizeLowestUpperBound(final ClassNode lub, final ClassNode a, final ClassNode b, final ClassNode fallback) {
259259
if (!lub.isUsingGenerics()) return lub;
260+
// GRECLIPSE add -- GROOVY-10229, GROOVY-10347
261+
if (a.toString(false).equals(b.toString(false))) return lub;
262+
// GRECLIPSE end
260263
// a common super type exists, all we have to do is to parameterize
261264
// it according to the types provided by the two class nodes
262265
ClassNode holderForA = findGenericsTypeHolderForClass(a, lub);
@@ -269,13 +272,8 @@ private static ClassNode parameterizeLowestUpperBound(final ClassNode lub, final
269272
}
270273
GenericsType[] lubgt = new GenericsType[agt.length];
271274
for (int i = 0; i < agt.length; i++) {
272-
/* GRECLIPSE edit -- GROOVY-10229
273275
ClassNode t1 = agt[i].getType();
274276
ClassNode t2 = bgt[i].getType();
275-
*/
276-
ClassNode t1 = upperBound(agt[i]);
277-
ClassNode t2 = upperBound(bgt[i]);
278-
// GRECLIPSE end
279277
ClassNode basicType;
280278
/* GRECLIPSE edit -- GROOVY-8111
281279
if (areEqualWithGenerics(t1, a) && areEqualWithGenerics(t2,b)) {
@@ -287,7 +285,7 @@ private static ClassNode parameterizeLowestUpperBound(final ClassNode lub, final
287285
} else {
288286
basicType = lowestUpperBound(t1, t2);
289287
}
290-
if (t1.equals(t2)/*GRECLIPSE add*/&& !agt[i].isWildcard()/**/) {
288+
if (t1.equals(t2)) {
291289
lubgt[i] = new GenericsType(basicType);
292290
} else {
293291
lubgt[i] = GenericsUtils.buildWildcardType(basicType);
@@ -298,16 +296,6 @@ private static ClassNode parameterizeLowestUpperBound(final ClassNode lub, final
298296
return plain;
299297
}
300298

301-
// GRECLIPSE add
302-
private static ClassNode upperBound(final GenericsType gt) {
303-
if (gt.isWildcard()) {
304-
ClassNode[] ub = gt.getUpperBounds();
305-
return ub != null ? ub[0] : OBJECT_TYPE;
306-
}
307-
return gt.getType();
308-
}
309-
// GRECLIPSE end
310-
311299
private static ClassNode findGenericsTypeHolderForClass(ClassNode source, ClassNode type) {
312300
if (isPrimitiveType(source)) source = getWrapper(source);
313301
if (source.equals(type)) return source;

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

+7-6
Original file line numberDiff line numberDiff line change
@@ -2039,7 +2039,7 @@ private static void extractGenericsConnections(Map<GenericsTypeName, GenericsTyp
20392039
if (ui.isWildcard()) {
20402040
extractGenericsConnections(connections, ui.getLowerBound(), lowerBound);
20412041
extractGenericsConnections(connections, ui.getUpperBounds(), upperBounds);
2042-
/* GRECLIPSE edit
2042+
/* GRECLIPSE edit -- GROOVY-9998
20432043
} else {
20442044
ClassNode cu = ui.getType();
20452045
extractGenericsConnections(connections, cu, di.getLowerBound());
@@ -2051,12 +2051,13 @@ private static void extractGenericsConnections(Map<GenericsTypeName, GenericsTyp
20512051
}
20522052
}
20532053
*/
2054-
} else if (lowerBound == null && upperBounds != null && upperBounds.length == 1) { // GROOVY-10347
2055-
if (upperBounds[0].isGenericsPlaceHolder()) { // GROOVY-9998: preserve wildcard semantic
2054+
} else if (!isUnboundedWildcard(di)) {
2055+
ClassNode boundType = lowerBound != null ? lowerBound : upperBounds[0];
2056+
if (boundType.isGenericsPlaceHolder()) {
20562057
ui = new GenericsType(ui.getType()); ui.setPlaceHolder(false); ui.setWildcard(true);
2057-
connections.put(new GenericsTypeName(upperBounds[0].getUnresolvedName()), ui);
2058-
} else { // di like "? extends Iterable<T>" and ui like "Collection<Type>"
2059-
extractGenericsConnections(connections, ui.getType(), upperBounds[0]);
2058+
connections.put(new GenericsTypeName(boundType.getUnresolvedName()), ui);
2059+
} else { // di like "? super Iterable<T>" and ui like "Collection<Type>"
2060+
extractGenericsConnections(connections, ui.getType(), boundType);
20602061
}
20612062
}
20622063
// GRECLIPSE end

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

+2-6
Original file line numberDiff line numberDiff line change
@@ -3610,7 +3610,7 @@ protected void inferClosureParameterTypes(final ClassNode receiver, final Expres
36103610
} else {
36113611
paramTypes = new ClassNode[n];
36123612
for (int i = 0; i < n; i += 1) {
3613-
paramTypes[i] = !p[i].isDynamicTyped() ? p[i].getOriginType() : (i < samParamTypes.length ? samParamTypes[i] : null);
3613+
paramTypes[i] = i < samParamTypes.length ? samParamTypes[i] : null;
36143614
}
36153615
}
36163616
expression.putNodeMetaData(StaticTypesMarker.CLOSURE_ARGUMENTS, paramTypes);
@@ -6368,11 +6368,7 @@ private Map<GenericsTypeName, GenericsType> extractGenericsConnectionsFromArgume
63686368
Map<GenericsTypeName, GenericsType> connections = new HashMap<>();
63696369
extractGenericsConnections(connections, wrapTypeIfNecessary(argumentType), paramType);
63706370
connections.forEach((gtn, gt) -> resolvedPlaceholders.merge(gtn, gt, (gt1, gt2) -> {
6371-
// GRECLIPSE add -- GROOVY-10347
6372-
if (gt1.toString().equals(gt2.toString()))
6373-
// GRECLIPSE end
6374-
return gt1;
6375-
// GRECLIPSE add -- GROOVY-10339: incorporate additional witness
6371+
// GRECLIPSE edit -- GROOVY-10339: incorporate another witness
63766372
ClassNode cn1 = GenericsUtils.makeClassSafe0(CLASS_Type, gt1);
63776373
ClassNode cn2 = GenericsUtils.makeClassSafe0(CLASS_Type, gt2);
63786374
return lowestUpperBound(cn1,cn2).getGenericsTypes()[0];

base/org.codehaus.groovy30/src/org/codehaus/groovy/ast/tools/WideningCategories.java

+4-16
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,9 @@ public static ClassNode lowestUpperBound(ClassNode a, ClassNode b) {
255255
*/
256256
private static ClassNode parameterizeLowestUpperBound(final ClassNode lub, final ClassNode a, final ClassNode b, final ClassNode fallback) {
257257
if (!lub.isUsingGenerics()) return lub;
258+
// GRECLIPSE add -- GROOVY-10229, GROOVY-10347
259+
if (a.toString(false).equals(b.toString(false))) return lub;
260+
// GRECLIPSE end
258261
// a common super type exists, all we have to do is to parameterize
259262
// it according to the types provided by the two class nodes
260263
ClassNode holderForA = findGenericsTypeHolderForClass(a, lub);
@@ -267,21 +270,16 @@ private static ClassNode parameterizeLowestUpperBound(final ClassNode lub, final
267270
}
268271
GenericsType[] lubgt = new GenericsType[agt.length];
269272
for (int i = 0; i < agt.length; i++) {
270-
/* GRECLIPSE edit -- GROOVY-10229
271273
ClassNode t1 = agt[i].getType();
272274
ClassNode t2 = bgt[i].getType();
273-
*/
274-
ClassNode t1 = upperBound(agt[i]);
275-
ClassNode t2 = upperBound(bgt[i]);
276-
// GRECLIPSE end
277275
ClassNode basicType;
278276
if (areEqualWithGenerics(t1, isPrimitiveType(a)?getWrapper(a):a) && areEqualWithGenerics(t2, isPrimitiveType(b)?getWrapper(b):b)) {
279277
// we are facing a self referencing type !
280278
basicType = fallback;
281279
} else {
282280
basicType = lowestUpperBound(t1, t2);
283281
}
284-
if (t1.equals(t2)/*GRECLIPSE add*/&& !agt[i].isWildcard()/**/) {
282+
if (t1.equals(t2)) {
285283
lubgt[i] = new GenericsType(basicType);
286284
} else {
287285
lubgt[i] = GenericsUtils.buildWildcardType(basicType);
@@ -292,16 +290,6 @@ private static ClassNode parameterizeLowestUpperBound(final ClassNode lub, final
292290
return plain;
293291
}
294292

295-
// GRECLIPSE add
296-
private static ClassNode upperBound(final GenericsType gt) {
297-
if (gt.isWildcard()) {
298-
ClassNode[] ub = gt.getUpperBounds();
299-
return ub != null ? ub[0] : OBJECT_TYPE;
300-
}
301-
return gt.getType();
302-
}
303-
// GRECLIPSE end
304-
305293
private static ClassNode findGenericsTypeHolderForClass(ClassNode source, ClassNode type) {
306294
if (isPrimitiveType(source)) source = getWrapper(source);
307295
if (source.equals(type)) return source;

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

+6-5
Original file line numberDiff line numberDiff line change
@@ -1924,12 +1924,13 @@ private static void extractGenericsConnections(final Map<GenericsTypeName, Gener
19241924
}
19251925
}
19261926
*/
1927-
} else if (lowerBound == null && upperBounds != null && upperBounds.length == 1) { // GROOVY-10347
1928-
if (upperBounds[0].isGenericsPlaceHolder()) {
1927+
} else if (!isUnboundedWildcard(di)) {
1928+
ClassNode boundType = lowerBound != null ? lowerBound : upperBounds[0];
1929+
if (boundType.isGenericsPlaceHolder()) {
19291930
ui = new GenericsType(ui.getType()); ui.setPlaceHolder(false); ui.setWildcard(true);
1930-
connections.put(new GenericsTypeName(upperBounds[0].getUnresolvedName()), ui);
1931-
} else { // di like "? extends Iterable<T>" and ui like "Collection<Type>"
1932-
extractGenericsConnections(connections, ui.getType(), upperBounds[0]);
1931+
connections.put(new GenericsTypeName(boundType.getUnresolvedName()), ui);
1932+
} else { // di like "? super Iterable<T>" and ui like "Collection<Type>"
1933+
extractGenericsConnections(connections, ui.getType(), boundType);
19331934
}
19341935
}
19351936
// GRECLIPSE end

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

+2-6
Original file line numberDiff line numberDiff line change
@@ -3277,7 +3277,7 @@ protected void inferClosureParameterTypes(final ClassNode receiver, final Expres
32773277
} else {
32783278
paramTypes = new ClassNode[n];
32793279
for (int i = 0; i < n; i += 1) {
3280-
paramTypes[i] = !p[i].isDynamicTyped() ? p[i].getOriginType() : (i < samParamTypes.length ? samParamTypes[i] : null);
3280+
paramTypes[i] = i < samParamTypes.length ? samParamTypes[i] : null;
32813281
}
32823282
}
32833283
expression.putNodeMetaData(CLOSURE_ARGUMENTS, paramTypes);
@@ -6038,11 +6038,7 @@ private Map<GenericsTypeName, GenericsType> extractGenericsConnectionsFromArgume
60386038
Map<GenericsTypeName, GenericsType> connections = new HashMap<>();
60396039
extractGenericsConnections(connections, wrapTypeIfNecessary(argumentType), paramType);
60406040
connections.forEach((gtn, gt) -> resolvedPlaceholders.merge(gtn, gt, (gt1, gt2) -> {
6041-
// GRECLIPSE add -- GROOVY-10347
6042-
if (gt1.toString().equals(gt2.toString()))
6043-
// GRECLIPSE end
6044-
return gt1;
6045-
// GRECLIPSE add -- GROOVY-10339: incorporate additional witness
6041+
// GRECLIPSE edit -- GROOVY-10339: incorporate another witness
60466042
ClassNode cn1 = GenericsUtils.makeClassSafe0(CLASS_Type, gt1);
60476043
ClassNode cn2 = GenericsUtils.makeClassSafe0(CLASS_Type, gt2);
60486044
return lowestUpperBound(cn1,cn2).getGenericsTypes()[0];

0 commit comments

Comments
 (0)