Skip to content

Commit 5077522

Browse files
committed
GROOVY-10055, GROOVY-10166
1 parent c0a8850 commit 5077522

File tree

7 files changed

+96
-37
lines changed

7 files changed

+96
-37
lines changed

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

+40-8
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,13 @@ public void testTypeChecked12() {
277277
};
278278
//@formatter:on
279279

280-
runNegativeTest(sources, "");
280+
runNegativeTest(sources,
281+
"----------\n" +
282+
"1. ERROR in Main.groovy (at line 4)\n" +
283+
"\tSet<String> keys = args.keySet()\n" +
284+
"\t ^^^^^^^^^^^^^\n" +
285+
"Groovy:[Static type checking] - Incompatible generic argument types. Cannot assign java.util.Set<java.lang.Object> to: java.util.Set<java.lang.String>\n" +
286+
"----------\n");
281287
}
282288

283289
@Test
@@ -3280,6 +3286,38 @@ public void testTypeChecked10053() {
32803286
runConformTest(sources, "[42]");
32813287
}
32823288

3289+
@Test
3290+
public void testTypeChecked10055() {
3291+
//@formatter:off
3292+
String[] sources = {
3293+
"Main.groovy",
3294+
"@groovy.transform.TypeChecked\n" +
3295+
"void test() {\n" +
3296+
" new C<>().foo('x').bar('y').baz('z')\n" +
3297+
"}\n",
3298+
3299+
"Types.groovy",
3300+
"abstract class A<Self extends A<Self>> {\n" +
3301+
" Self foo(inputs) {\n" +
3302+
" this\n" +
3303+
" }\n" +
3304+
"}\n" +
3305+
"abstract class B<Self extends B<Self>> extends A<Self> {\n" +
3306+
" Self bar(inputs) {\n" +
3307+
" this\n" +
3308+
" }\n" +
3309+
"}\n" +
3310+
"class C<Self extends C<Self>> extends B<Self> {\n" +
3311+
" Self baz(inputs) {\n" +
3312+
" this\n" +
3313+
" }\n" +
3314+
"}\n",
3315+
};
3316+
//@formatter:on
3317+
3318+
runNegativeTest(sources, "");
3319+
}
3320+
32833321
@Test
32843322
public void testTypeChecked10056() {
32853323
//@formatter:off
@@ -3681,13 +3719,7 @@ public void testTypeChecked10166() {
36813719
};
36823720
//@formatter:on
36833721

3684-
runNegativeTest(sources,
3685-
"----------\n" +
3686-
"1. ERROR in Main.groovy (at line 17)\n" +
3687-
"\ta.c.get(1)\n" +
3688-
"\t^^^^^^^^^^\n" +
3689-
"Groovy:[Static type checking] - Cannot find matching method T#get(int). Please check if the declared type is correct and if the method exists.\n" +
3690-
"----------\n");
3722+
runConformTest(sources);
36913723
}
36923724

36933725
@Test

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

+14-2
Original file line numberDiff line numberDiff line change
@@ -6715,7 +6715,6 @@ private static boolean isGenericsPlaceHolderOrArrayOf(ClassNode cn) {
67156715
return cn.isGenericsPlaceHolder();
67166716
}
67176717

6718-
67196718
private static Map<GenericsTypeName, GenericsType> extractPlaceHolders(MethodNode method, ClassNode receiver, ClassNode declaringClass) {
67206719
if (declaringClass.equals(OBJECT_TYPE)) {
67216720
Map<GenericsTypeName, GenericsType> resolvedPlaceholders = new HashMap<GenericsTypeName, GenericsType>();
@@ -6737,8 +6736,18 @@ private static Map<GenericsTypeName, GenericsType> extractPlaceHolders(MethodNod
67376736
ClassNode current = item;
67386737
while (current != null) {
67396738
boolean continueLoop = true;
6740-
//extract the place holders
6739+
// extract the place holders
67416740
Map<GenericsTypeName, GenericsType> currentPlaceHolders = new HashMap<GenericsTypeName, GenericsType>();
6741+
// GRECLIPSE add -- GROOVY-10055, GROOVY-10166
6742+
if (current.getGenericsTypes() != null
6743+
? current.getGenericsTypes().length == 0
6744+
: current.redirect().getGenericsTypes() != null) {
6745+
for (GenericsType gt : current.redirect().getGenericsTypes()) {
6746+
ClassNode cn = gt.getUpperBounds() != null ? gt.getUpperBounds()[0] : gt.getType().redirect();
6747+
currentPlaceHolders.put(new GenericsTypeName(gt.getName()), cn.getPlainNodeReference().asGenericsType());
6748+
}
6749+
}
6750+
// GRECLIPSE end
67426751
if (isGenericsPlaceHolderOrArrayOf(declaringClass) || declaringClass.equals(current)) {
67436752
extractGenericsConnections(currentPlaceHolders, current, declaringClass);
67446753
if (method != null) addMethodLevelDeclaredGenerics(method, currentPlaceHolders);
@@ -6769,6 +6778,9 @@ private static Map<GenericsTypeName, GenericsType> extractPlaceHolders(MethodNod
67696778
// the actual receiver is Foo and declaringClass is Class
67706779
current = declaringClass;
67716780
}
6781+
// GRECLIPSE add -- GROOVY-10055, GROOVY-10166
6782+
else current = applyGenericsContext(currentPlaceHolders, current);
6783+
// GRECLIPSE end
67726784
}
67736785
}
67746786
if (resolvedPlaceholders == null) {

base/org.codehaus.groovy30/src/groovy/grape/GrapeIvy.groovy

+1-1
Original file line numberDiff line numberDiff line change
@@ -649,7 +649,7 @@ class GrapeIvy implements GrapeEngine {
649649

650650
URI[] resolve(ClassLoader loader, Map args, List depsInfo, Map... dependencies) {
651651
// check for mutually exclusive arguments
652-
Set<String> keys = args.keySet()
652+
Set<String> keys = (Set<String>) args.keySet()
653653
keys.each { key ->
654654
Set<String> badArgs = MUTUALLY_EXCLUSIVE_KEYS[key]
655655
if (badArgs && !badArgs.disjoint(keys)) {

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

+13
Original file line numberDiff line numberDiff line change
@@ -6380,6 +6380,16 @@ private static Map<GenericsTypeName, GenericsType> extractPlaceHolders(final Met
63806380
boolean continueLoop = true;
63816381
// extract the place holders
63826382
Map<GenericsTypeName, GenericsType> currentPlaceHolders = new HashMap<>();
6383+
// GRECLIPSE add -- GROOVY-10055, GROOVY-10166
6384+
if (current.getGenericsTypes() != null
6385+
? current.getGenericsTypes().length == 0
6386+
: current.redirect().getGenericsTypes() != null) {
6387+
for (GenericsType gt : current.redirect().getGenericsTypes()) {
6388+
ClassNode cn = gt.getUpperBounds() != null ? gt.getUpperBounds()[0] : gt.getType().redirect();
6389+
currentPlaceHolders.put(new GenericsTypeName(gt.getName()), cn.getPlainNodeReference().asGenericsType());
6390+
}
6391+
}
6392+
// GRECLIPSE end
63836393
if (isGenericsPlaceHolderOrArrayOf(declaringClass) || declaringClass.equals(current)) {
63846394
extractGenericsConnections(currentPlaceHolders, current, declaringClass);
63856395
if (method != null) addMethodLevelDeclaredGenerics(method, currentPlaceHolders);
@@ -6410,6 +6420,9 @@ private static Map<GenericsTypeName, GenericsType> extractPlaceHolders(final Met
64106420
// the actual receiver is Foo and declaringClass is Class
64116421
current = declaringClass;
64126422
}
6423+
// GRECLIPSE add -- GROOVY-10055, GROOVY-10166
6424+
else current = applyGenericsContext(currentPlaceHolders, current);
6425+
// GRECLIPSE end
64136426
}
64146427
}
64156428
if (resolvedPlaceholders == null) {

base/org.codehaus.groovy40/src/groovy/grape/GrapeIvy.groovy

+1-1
Original file line numberDiff line numberDiff line change
@@ -649,7 +649,7 @@ class GrapeIvy implements GrapeEngine {
649649

650650
URI[] resolve(ClassLoader loader, Map args, List depsInfo, Map... dependencies) {
651651
// check for mutually exclusive arguments
652-
Set<String> keys = args.keySet()
652+
Set<String> keys = (Set<String>) args.keySet()
653653
keys.each { key ->
654654
Set<String> badArgs = MUTUALLY_EXCLUSIVE_KEYS[key]
655655
if (badArgs && !badArgs.disjoint(keys)) {

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

+25-24
Original file line numberDiff line numberDiff line change
@@ -5795,7 +5795,7 @@ && isClassType(receiver)
57955795
}
57965796

57975797
private static Map<GenericsTypeName, GenericsType> extractPlaceHolders(final MethodNode method, ClassNode receiver, final ClassNode declaringClass) {
5798-
Map<GenericsTypeName, GenericsType> resolvedPlaceholders = null;
5798+
Map<GenericsTypeName, GenericsType> resolvedPlaceHolders = null;
57995799
if (isPrimitiveType(receiver) && !isPrimitiveType(declaringClass)) {
58005800
receiver = getWrapper(receiver);
58015801
}
@@ -5808,54 +5808,55 @@ private static Map<GenericsTypeName, GenericsType> extractPlaceHolders(final Met
58085808
for (ClassNode type : todo) {
58095809
ClassNode current = type;
58105810
while (current != null) {
5811-
boolean continueLoop = true;
5812-
// extract the place holders
58135811
Map<GenericsTypeName, GenericsType> currentPlaceHolders = new HashMap<>();
5814-
if (isGenericsPlaceHolderOrArrayOf(declaringClass) || declaringClass.equals(current)) {
5812+
// GROOVY-10055: handle diamond or raw
5813+
if (current.getGenericsTypes() != null
5814+
? current.getGenericsTypes().length == 0
5815+
: current.redirect().getGenericsTypes() != null) {
5816+
for (GenericsType gt : current.redirect().getGenericsTypes()) {
5817+
ClassNode cn = gt.getUpperBounds() != null ? gt.getUpperBounds()[0] : gt.getType().redirect();
5818+
currentPlaceHolders.put(new GenericsTypeName(gt.getName()), cn.getPlainNodeReference().asGenericsType());
5819+
}
5820+
}
5821+
5822+
boolean currentIsDeclaring = current.equals(declaringClass) || isGenericsPlaceHolderOrArrayOf(declaringClass);
5823+
if (currentIsDeclaring) {
58155824
extractGenericsConnections(currentPlaceHolders, current, declaringClass);
5816-
if (method != null) addMethodLevelDeclaredGenerics(method, currentPlaceHolders);
5817-
continueLoop = false;
5825+
if (method != null)
5826+
addMethodLevelDeclaredGenerics(method, currentPlaceHolders);
58185827
} else {
58195828
GenericsUtils.extractPlaceholders(current, currentPlaceHolders);
58205829
}
58215830

5822-
if (resolvedPlaceholders != null) {
5823-
// merge maps
5831+
if (resolvedPlaceHolders != null) { // merge maps
58245832
for (Map.Entry<GenericsTypeName, GenericsType> entry : currentPlaceHolders.entrySet()) {
58255833
GenericsType gt = entry.getValue();
58265834
if (!gt.isPlaceholder()) continue;
5827-
GenericsType referenced = resolvedPlaceholders.get(new GenericsTypeName(gt.getName()));
5835+
GenericsType referenced = resolvedPlaceHolders.get(new GenericsTypeName(gt.getName()));
58285836
if (referenced == null) continue;
58295837
entry.setValue(referenced);
58305838
}
58315839
}
5832-
resolvedPlaceholders = currentPlaceHolders;
5840+
resolvedPlaceHolders = currentPlaceHolders;
58335841

58345842
// we are done if we are now in the declaring class
5835-
if (!continueLoop) break;
5843+
if (currentIsDeclaring) break;
58365844

5837-
boolean isRawType = (current.getGenericsTypes() == null
5838-
&& current.redirect().getGenericsTypes() != null);
58395845
current = getNextSuperClass(current, declaringClass);
58405846
if (current == null && isClassType(declaringClass)) {
58415847
// this can happen if the receiver is Class<Foo>, then
58425848
// the actual receiver is Foo and declaringClass is Class
58435849
current = declaringClass;
5844-
} else if (isRawType) {
5845-
current = current.getPlainNodeReference();
5850+
} else {
5851+
current = applyGenericsContext(currentPlaceHolders, current);
58465852
}
58475853
}
58485854
}
5849-
if (resolvedPlaceholders == null) {
5850-
String descriptor = "<>";
5851-
if (method != null) descriptor = method.getTypeDescriptor();
5852-
throw new GroovyBugError(
5853-
"Declaring class for method call to '" +
5854-
descriptor + "' declared in " + declaringClass.getName() +
5855-
" was not matched with found receiver " + receiver.getName() + "." +
5856-
" This should not have happened!");
5855+
if (resolvedPlaceHolders == null) {
5856+
throw new GroovyBugError("Declaring class for method call to '" + (method != null ? method.getTypeDescriptor() : "<>") +
5857+
"' declared in " + declaringClass.getName() + " was not matched with found receiver " + receiver.getName() + ". This should not have happened!");
58575858
}
5858-
return resolvedPlaceholders;
5859+
return resolvedPlaceHolders;
58595860
}
58605861

58615862
protected boolean typeCheckMethodsWithGenericsOrFail(final ClassNode receiver, final ClassNode[] arguments, final MethodNode candidateMethod, final Expression location) {

base/org.eclipse.jdt.groovy.core/src/org/eclipse/jdt/groovy/search/GenericsMapper.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,8 @@ public static GenericsMapper gatherGenerics(final ClassNode resolvedType, final
9494
if (n > 0 && rgts.length == 0) {
9595
rgts = new GenericsType[n]; // assume rCandidate is a raw type
9696
for (int i = 0; i < n; i += 1) {
97-
rgts[i] = new GenericsType(Optional.ofNullable(ugts[i].getUpperBounds()).map(bounds -> bounds[0]).orElse(VariableScope.OBJECT_CLASS_NODE));
97+
rgts[i] = new GenericsType(Optional.ofNullable(ugts[i].getUpperBounds()).map(bounds -> bounds[0])
98+
.orElse(ugts[i].getType().redirect()).getPlainNodeReference()); // GROOVY-10055, GROOVY-10166
9899
}
99100
}
100101
assert rgts.length == ugts.length;

0 commit comments

Comments
 (0)