Skip to content

Commit 3e5aebd

Browse files
committed
GROOVY-10347
1 parent a0d1141 commit 3e5aebd

File tree

7 files changed

+81
-28
lines changed

7 files changed

+81
-28
lines changed

base-test/org.eclipse.jdt.groovy.core.tests.builder/src/org/eclipse/jdt/core/groovy/tests/search/GenericInferencingTests.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -942,7 +942,7 @@ public void testClosure7() {
942942
String contents =
943943
"class C<T> {\n" +
944944
" static <U> C<U> of(U item) {}\n" +
945-
" def <V> C<V> map(F<? super T, ? super V> func) {}\n" +
945+
" def <V> C<V> map(F<? super T, ? extends V> func) {}\n" +
946946
"}\n" +
947947
"class D {\n" +
948948
" static <W> Set<W> wrap(W o) {}\n" +

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -6336,7 +6336,7 @@ public void testCompileStatic10047() {
63366336
"@groovy.transform.CompileStatic\n" +
63376337
"void test() {\n" +
63386338
" print(['a','bc','def'].stream().collect(toMap(Function.<String>identity(), String::length)))\n" +
6339-
"}\n" +
6339+
"}\n" + // <T,K,U> Collector<T,?,Map<K,U>> toMap(Function<? super T,? extends K>,Function<? super T,? extends U>)
63406340
"test()\n",
63416341
};
63426342
//@formatter:on

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

+48-1
Original file line numberDiff line numberDiff line change
@@ -2162,7 +2162,7 @@ public void testTypeChecked9873() {
21622162
" static <U> C<U> of(U item) {\n" +
21632163
" new C<U>(item)\n" +
21642164
" }\n" +
2165-
" def <V> C<V> map(F<? super T, ? super V> func) {\n" +
2165+
" def <V> C<V> map(F<? super T, ? extends V> func) {\n" +
21662166
" new C<V>(func.apply(t))\n" +
21672167
" }\n" +
21682168
"}\n" +
@@ -4658,4 +4658,51 @@ public void testTypeChecked10344() {
46584658

46594659
runConformTest(sources);
46604660
}
4661+
4662+
@Test
4663+
public void testTypeChecked10347() {
4664+
//@formatter:off
4665+
String[] sources = {
4666+
"Main.groovy",
4667+
"@groovy.transform.TypeChecked\n" +
4668+
"void test() {\n" +
4669+
" String[] one = ['foo','bar'], two = ['baz']\n" +
4670+
" Map<String,Integer> map = one.collectEntries{[it,1]} + two.collectEntries{[it,2]}\n" +
4671+
" print map\n" +
4672+
"}\n" +
4673+
"test()\n",
4674+
};
4675+
//@formatter:on
4676+
4677+
runConformTest(sources, "[foo:1, bar:1, baz:2]");
4678+
}
4679+
4680+
@Test
4681+
public void testTypeChecked10347a() {
4682+
//@formatter:off
4683+
String[] sources = {
4684+
"Main.groovy",
4685+
"@groovy.transform.TypeChecked\n" +
4686+
"void test(Pogo[] pogos) {\n" +
4687+
" List<String> strings = pogos.sort(true, new Sorter()).collect { Pogo pogo ->\n" + // static <T> T[] sort(T[], boolean, Comparator<? super T>)
4688+
" pogo.x\n" +
4689+
" }\n" +
4690+
" print strings\n" +
4691+
"}\n" +
4692+
"test(new Pogo(x:'foo'),new Pogo(x:'bar'))\n",
4693+
4694+
"Pogo.groovy",
4695+
"class Pogo {\n" +
4696+
" String x\n" +
4697+
"}\n",
4698+
4699+
"Sorter.groovy",
4700+
"class Sorter implements Comparator<Pogo>, Serializable {\n" +
4701+
" int compare(Pogo p1, Pogo p2) { p1.x <=> p2.x }\n" +
4702+
"}\n",
4703+
};
4704+
//@formatter:on
4705+
4706+
runConformTest(sources, "[bar, foo]");
4707+
}
46614708
}

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

+9-10
Original file line numberDiff line numberDiff line change
@@ -2034,10 +2034,11 @@ private static void extractGenericsConnections(Map<GenericsTypeName, GenericsTyp
20342034
if (di.isPlaceholder()) {
20352035
connections.put(new GenericsTypeName(di.getName()), ui);
20362036
} else if (di.isWildcard()) {
2037+
ClassNode lowerBound = di.getLowerBound(), upperBounds[] = di.getUpperBounds();
20372038
if (ui.isWildcard()) {
2038-
extractGenericsConnections(connections, ui.getLowerBound(), di.getLowerBound());
2039-
extractGenericsConnections(connections, ui.getUpperBounds(), di.getUpperBounds());
2040-
/* GRECLIPSE edit -- GROOVY-9998
2039+
extractGenericsConnections(connections, ui.getLowerBound(), lowerBound);
2040+
extractGenericsConnections(connections, ui.getUpperBounds(), upperBounds);
2041+
/* GRECLIPSE edit
20412042
} else {
20422043
ClassNode cu = ui.getType();
20432044
extractGenericsConnections(connections, cu, di.getLowerBound());
@@ -2049,14 +2050,12 @@ private static void extractGenericsConnections(Map<GenericsTypeName, GenericsTyp
20492050
}
20502051
}
20512052
*/
2052-
} else if (!isUnboundedWildcard(di)) {
2053-
ClassNode boundType = di.getLowerBound() != null ? di.getLowerBound() : di.getUpperBounds()[0];
2054-
if (boundType.isGenericsPlaceHolder()) {
2055-
String placeholderName = boundType.getUnresolvedName();
2053+
} else if (lowerBound == null && upperBounds != null && upperBounds.length == 1) { // GROOVY-10347
2054+
if (upperBounds[0].isGenericsPlaceHolder()) { // GROOVY-9998: preserve wildcard semantic
20562055
ui = new GenericsType(ui.getType()); ui.setPlaceHolder(false); ui.setWildcard(true);
2057-
connections.put(new GenericsTypeName(placeholderName), ui);
2058-
} else { // di like "? super Collection<T>" and ui like "List<Type>"
2059-
extractGenericsConnections(connections, ui.getType(), boundType);
2056+
connections.put(new GenericsTypeName(upperBounds[0].getUnresolvedName()), ui);
2057+
} else { // di like "? extends Iterable<T>" and ui like "Collection<Type>"
2058+
extractGenericsConnections(connections, ui.getType(), upperBounds[0]);
20602059
}
20612060
}
20622061
// GRECLIPSE end

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

+7-3
Original file line numberDiff line numberDiff line change
@@ -3540,7 +3540,7 @@ protected void inferClosureParameterTypes(final ClassNode receiver, final Expres
35403540
doInferClosureParameterTypes(receiver, arguments, expression, selectedMethod, hintClass, resolverClass, options);
35413541
}
35423542
}
3543-
/* GRECLIPSE edit -- GROOVY-8917, GROOVY-9347, GROOVY-10049
3543+
/* GRECLIPSE edit -- GROOVY-8917, GROOVY-9347, GROOVY-10047, GROOVY-10049
35443544
} else if (isSAMType(param.getOriginType())) {
35453545
// SAM coercion
35463546
inferSAMType(param, receiver, selectedMethod, InvocationWriter.makeArgumentList(arguments), expression);
@@ -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] = i < samParamTypes.length ? samParamTypes[i] : null;
3613+
paramTypes[i] = !p[i].isDynamicTyped() ? p[i].getOriginType() : (i < samParamTypes.length ? samParamTypes[i] : null);
36143614
}
36153615
}
36163616
expression.putNodeMetaData(StaticTypesMarker.CLOSURE_ARGUMENTS, paramTypes);
@@ -6368,7 +6368,11 @@ 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 edit -- GROOVY-10339: incorporate additional witness
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
63726376
ClassNode cn1 = GenericsUtils.makeClassSafe0(CLASS_Type, gt1);
63736377
ClassNode cn2 = GenericsUtils.makeClassSafe0(CLASS_Type, gt2);
63746378
return lowestUpperBound(cn1,cn2).getGenericsTypes()[0];

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

+8-9
Original file line numberDiff line numberDiff line change
@@ -1907,9 +1907,10 @@ private static void extractGenericsConnections(final Map<GenericsTypeName, Gener
19071907
if (di.isPlaceholder()) {
19081908
connections.put(new GenericsTypeName(di.getName()), ui);
19091909
} else if (di.isWildcard()) {
1910+
ClassNode lowerBound = di.getLowerBound(), upperBounds[] = di.getUpperBounds();
19101911
if (ui.isWildcard()) {
1911-
extractGenericsConnections(connections, ui.getLowerBound(), di.getLowerBound());
1912-
extractGenericsConnections(connections, ui.getUpperBounds(), di.getUpperBounds());
1912+
extractGenericsConnections(connections, ui.getLowerBound(), lowerBound);
1913+
extractGenericsConnections(connections, ui.getUpperBounds(), upperBounds);
19131914
/* GRECLIPSE edit -- GROOVY-9998, GROOVY-10327
19141915
} else {
19151916
ClassNode cu = ui.getType();
@@ -1922,14 +1923,12 @@ private static void extractGenericsConnections(final Map<GenericsTypeName, Gener
19221923
}
19231924
}
19241925
*/
1925-
} else if (!isUnboundedWildcard(di)) {
1926-
ClassNode boundType = di.getLowerBound() != null ? di.getLowerBound() : di.getUpperBounds()[0];
1927-
if (boundType.isGenericsPlaceHolder()) {
1928-
String placeholderName = boundType.getUnresolvedName();
1926+
} else if (lowerBound == null && upperBounds != null && upperBounds.length == 1) { // GROOVY-10347
1927+
if (upperBounds[0].isGenericsPlaceHolder()) {
19291928
ui = new GenericsType(ui.getType()); ui.setPlaceHolder(false); ui.setWildcard(true);
1930-
connections.put(new GenericsTypeName(placeholderName), ui);
1931-
} else { // di like "? super Collection<T>" and ui like "List<Type>"
1932-
extractGenericsConnections(connections, ui.getType(), boundType);
1929+
connections.put(new GenericsTypeName(upperBounds[0].getUnresolvedName()), ui);
1930+
} else { // di like "? extends Iterable<T>" and ui like "Collection<Type>"
1931+
extractGenericsConnections(connections, ui.getType(), upperBounds[0]);
19331932
}
19341933
}
19351934
// GRECLIPSE end

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

+7-3
Original file line numberDiff line numberDiff line change
@@ -3212,7 +3212,7 @@ protected void inferClosureParameterTypes(final ClassNode receiver, final Expres
32123212
}
32133213
}
32143214
} else if (isSAMType(param.getOriginType())) {
3215-
/* GRECLIPSE edit -- GROOVY-8917, GROOVY-10049
3215+
/* GRECLIPSE edit -- GROOVY-8917, GROOVY-10047, GROOVY-10049
32163216
inferSAMType(param, receiver, selectedMethod, InvocationWriter.makeArgumentList(arguments), expression);
32173217
*/
32183218
Map<GenericsTypeName, GenericsType> context = selectedMethod.isStatic() ? new HashMap<>() : extractPlaceHolders(null, receiver, getDeclaringClass(selectedMethod, arguments));
@@ -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] = i < samParamTypes.length ? samParamTypes[i] : null;
3280+
paramTypes[i] = !p[i].isDynamicTyped() ? p[i].getOriginType() : (i < samParamTypes.length ? samParamTypes[i] : null);
32813281
}
32823282
}
32833283
expression.putNodeMetaData(CLOSURE_ARGUMENTS, paramTypes);
@@ -6038,7 +6038,11 @@ 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 edit -- GROOVY-10339: incorporate additional witness
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
60426046
ClassNode cn1 = GenericsUtils.makeClassSafe0(CLASS_Type, gt1);
60436047
ClassNode cn2 = GenericsUtils.makeClassSafe0(CLASS_Type, gt2);
60446048
return lowestUpperBound(cn1,cn2).getGenericsTypes()[0];

0 commit comments

Comments
 (0)