Skip to content

Commit 8311a93

Browse files
committed
GROOVY-6786, GROOVY-9902
1 parent 9c2f026 commit 8311a93

File tree

7 files changed

+100
-4
lines changed

7 files changed

+100
-4
lines changed

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

+78
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,31 @@ public void testTypeChecked9() {
218218
runNegativeTest(sources, "");
219219
}
220220

221+
@Test
222+
public void testTypeChecked6786() {
223+
//@formatter:off
224+
String[] sources = {
225+
"Main.groovy",
226+
"class C<X> {\n" +
227+
" Container<X> container\n" +
228+
" @groovy.transform.TypeChecked\n" +
229+
" void refresh() {\n" +
230+
" def items = findAllItems()\n" +
231+
" container.addAll(items)\n" + // Cannot call Container#addAll(java.util.Collection<? extends X>) with arguments [java.util.Collection<X>]
232+
" }\n" +
233+
" Collection<X> findAllItems() {\n" +
234+
" }\n" +
235+
"}\n" +
236+
"interface Container<Y> {\n" +
237+
" void addAll(Collection<? extends Y> collection)\n" +
238+
"}\n" +
239+
"new C()\n",
240+
};
241+
//@formatter:on
242+
243+
runNegativeTest(sources, "");
244+
}
245+
221246
@Test
222247
public void testTypeChecked6882() {
223248
//@formatter:off
@@ -633,6 +658,59 @@ public void testTypeChecked9873() {
633658
runConformTest(sources, "123", options);
634659
}
635660

661+
@Test
662+
public void testTypeChecked9902() {
663+
//@formatter:off
664+
String[] sources = {
665+
"Main.groovy",
666+
"class Holder<Unknown> {\n" +
667+
" TypedProperty<Number, Unknown> numberProperty = prop(Number)\n" +
668+
" TypedProperty<String, Unknown> stringProperty = prop(String)\n" +
669+
" def <T> TypedProperty<T, Unknown> prop(Class<T> clazz) {\n" +
670+
" new TypedProperty<T, Unknown>(clazz: clazz)\n" +
671+
" }\n" +
672+
// Note: type argument of Holder cannot be supplied to value attribute of @DelegatesTo
673+
" def <T> T of(@DelegatesTo(value=Holder, strategy=Closure.DELEGATE_FIRST) Closure<T> c) {\n" +
674+
" this.with(c)\n" +
675+
" }\n" +
676+
"}\n" +
677+
"class TypedProperty<X, Y> {\n" +
678+
" Class<X> clazz\n" +
679+
" void eq(X x) {\n" +
680+
" assert x.class == clazz : \"x.class is ${x.class} not ${clazz}\"\n" +
681+
" }\n" +
682+
"}\n" +
683+
"@groovy.transform.TypeChecked\n" +
684+
"void test(Holder<Object> h) {\n" +
685+
" h.stringProperty.eq(\"${0}\")\n" + // STC error
686+
" h.of {\n" + // <-- 2nd type parameter discarded
687+
" stringProperty.eq(1234)\n" + // expect STC error
688+
" numberProperty.eq('xx')\n" + // expect STC error
689+
" }\n" +
690+
"}\n" +
691+
"test(new Holder<Object>())\n",
692+
};
693+
//@formatter:on
694+
695+
runNegativeTest(sources,
696+
"----------\n" +
697+
"1. ERROR in Main.groovy (at line 19)\n" +
698+
"\th.stringProperty.eq(\"${0}\")\n" +
699+
"\t^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" +
700+
"Groovy:[Static type checking] - Cannot call TypedProperty <String, Object>#eq(java.lang.String) with arguments [groovy.lang.GString] \n" +
701+
"----------\n" +
702+
"2. ERROR in Main.groovy (at line 21)\n" +
703+
"\tstringProperty.eq(1234)\n" +
704+
"\t^^^^^^^^^^^^^^^^^^^^^^^\n" +
705+
"Groovy:[Static type checking] - Cannot call TypedProperty <String, Unknown>#eq(java.lang.String) with arguments [int] \n" +
706+
"----------\n" +
707+
"3. ERROR in Main.groovy (at line 22)\n" +
708+
"\tnumberProperty.eq('xx')\n" +
709+
"\t^^^^^^^^^^^^^^^^^^^^^^^\n" +
710+
"Groovy:[Static type checking] - Cannot call TypedProperty <Number, Unknown>#eq(java.lang.Number) with arguments [java.lang.String] \n" +
711+
"----------\n");
712+
}
713+
636714
@Test
637715
public void testTypeChecked9903() {
638716
//@formatter:off

base/org.codehaus.groovy25/src/org/codehaus/groovy/ast/GenericsType.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,7 @@ private boolean compareGenericsWithBound(final ClassNode classNode, final ClassN
407407
if (genericsType.isPlaceholder()) {
408408
match = true;
409409
} else if (genericsType.isWildcard()) {
410-
/* GRECLIPSE edit -- GROOVY-9460
410+
/* GRECLIPSE edit -- GROOVY-6786, GROOVY-9460, GROOVY-9902
411411
if (genericsType.getUpperBounds()!=null) {
412412
for (ClassNode up : genericsType.getUpperBounds()) {
413413
match |= redirectBoundType.isCompatibleWith(up);
@@ -417,10 +417,10 @@ private boolean compareGenericsWithBound(final ClassNode classNode, final ClassN
417417
}
418418
}
419419
*/
420-
if (genericsType.getUpperBounds() != null) { // multiple bounds not allowed for ?
421-
match = redirectBoundType.isCompatibleWith(genericsType.getUpperBounds()[0]);
420+
if (genericsType.getUpperBounds() != null) { // ? supports single bound only
421+
match = classNodeType.isCompatibleWith(genericsType.getUpperBounds()[0]);
422422
} else if (genericsType.getLowerBound() != null) {
423-
match = redirectBoundType.isCompatibleWith(genericsType.getLowerBound());
423+
match = classNodeType.isCompatibleWith(genericsType.getLowerBound());
424424
} else {
425425
match = true;
426426
}

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

+2
Original file line numberDiff line numberDiff line change
@@ -1463,9 +1463,11 @@ static void addMethodLevelDeclaredGenerics(MethodNode method, Map<GenericsTypeNa
14631463
}
14641464

14651465
protected static boolean typeCheckMethodsWithGenerics(ClassNode receiver, ClassNode[] arguments, MethodNode candidateMethod) {
1466+
/* GRECLIPSE edit -- GROOVY-9902
14661467
if (isUsingUncheckedGenerics(receiver)) {
14671468
return true;
14681469
}
1470+
*/
14691471
if (CLASS_Type.equals(receiver)
14701472
&& receiver.isUsingGenerics()
14711473
&& !candidateMethod.getDeclaringClass().equals(receiver)

base/org.codehaus.groovy30/src/org/codehaus/groovy/ast/GenericsType.java

+6
Original file line numberDiff line numberDiff line change
@@ -399,9 +399,15 @@ private static boolean compareGenericsWithBound(final ClassNode classNode, final
399399
match = true;
400400
} else if (genericsType.isWildcard()) {
401401
if (genericsType.getUpperBounds() != null) { // multiple bounds not allowed for ?
402+
/* GRECLIPSE edit -- GROOVY-6786, GROOVY-9902
402403
match = redirectBoundType.isCompatibleWith(genericsType.getUpperBounds()[0]);
403404
} else if (genericsType.getLowerBound() != null) {
404405
match = redirectBoundType.isCompatibleWith(genericsType.getLowerBound());
406+
*/
407+
match = classNodeType.isCompatibleWith(genericsType.getUpperBounds()[0]);
408+
} else if (genericsType.getLowerBound() != null) {
409+
match = classNodeType.isCompatibleWith(genericsType.getLowerBound());
410+
// GRECLIPSE end
405411
} else {
406412
match = true;
407413
}

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

+2
Original file line numberDiff line numberDiff line change
@@ -1388,9 +1388,11 @@ static void addMethodLevelDeclaredGenerics(final MethodNode method, final Map<Ge
13881388
}
13891389

13901390
protected static boolean typeCheckMethodsWithGenerics(final ClassNode receiver, final ClassNode[] argumentTypes, final MethodNode candidateMethod) {
1391+
/* GRECLIPSE edit -- GROOVY-9902
13911392
if (isUsingUncheckedGenerics(receiver)) {
13921393
return true;
13931394
}
1395+
*/
13941396
if (CLASS_Type.equals(receiver)
13951397
&& receiver.isUsingGenerics()
13961398
&& !candidateMethod.getDeclaringClass().equals(receiver)

base/org.codehaus.groovy40/src/org/codehaus/groovy/ast/GenericsType.java

+6
Original file line numberDiff line numberDiff line change
@@ -400,9 +400,15 @@ private static boolean compareGenericsWithBound(final ClassNode classNode, final
400400
match = true;
401401
} else if (genericsType.isWildcard()) {
402402
if (genericsType.getUpperBounds() != null) { // multiple bounds not allowed for ?
403+
/* GRECLIPSE edit -- GROOVY-6786, GROOVY-9902
403404
match = redirectBoundType.isCompatibleWith(genericsType.getUpperBounds()[0]);
404405
} else if (genericsType.getLowerBound() != null) {
405406
match = redirectBoundType.isCompatibleWith(genericsType.getLowerBound());
407+
*/
408+
match = classNodeType.isCompatibleWith(genericsType.getUpperBounds()[0]);
409+
} else if (genericsType.getLowerBound() != null) {
410+
match = classNodeType.isCompatibleWith(genericsType.getLowerBound());
411+
// GRECLIPSE end
406412
} else {
407413
match = true;
408414
}

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

+2
Original file line numberDiff line numberDiff line change
@@ -1386,9 +1386,11 @@ static void addMethodLevelDeclaredGenerics(final MethodNode method, final Map<Ge
13861386
}
13871387

13881388
protected static boolean typeCheckMethodsWithGenerics(final ClassNode receiver, final ClassNode[] argumentTypes, final MethodNode candidateMethod) {
1389+
/* GRECLIPSE edit -- GROOVY-9902
13891390
if (isUsingUncheckedGenerics(receiver)) {
13901391
return true;
13911392
}
1393+
*/
13921394
if (CLASS_Type.equals(receiver)
13931395
&& receiver.isUsingGenerics()
13941396
&& !candidateMethod.getDeclaringClass().equals(receiver)

0 commit comments

Comments
 (0)