Skip to content

Commit 2e1dbe2

Browse files
committed
GROOVY-10220, GROOVY-10235
1 parent d498406 commit 2e1dbe2

File tree

5 files changed

+179
-17
lines changed

5 files changed

+179
-17
lines changed

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

+13-9
Original file line numberDiff line numberDiff line change
@@ -1805,17 +1805,21 @@ public void testCompileStatic8176() {
18051805
String[] sources = {
18061806
"Main.groovy",
18071807
"@groovy.transform.CompileStatic\n" +
1808-
"static <M extends Map> M merge(M to, Map from) {\n" +
1809-
" !from ? to : to.with {\n" +
1810-
" one = from['one']\n" +
1811-
" two = from['two']\n" +
1812-
" return it\n" +
1808+
"static <P extends Pogo> P merge(P pogo, Map spec) {\n" +
1809+
" !spec ? pogo : pogo.tap {\n" +
1810+
" one = spec['one']\n" +
1811+
" two = spec['two']\n" +
18131812
" }\n" +
18141813
"}\n" +
1815-
"def map = [:]\n" +
1816-
"def result = merge(map, [one: 1, two: 2.0])\n" +
1817-
"assert result == [one: 1, two: 2.0]\n" +
1818-
"assert result.is(map)\n",
1814+
"def pogo = new Pogo()\n" +
1815+
"def result = merge(pogo, [one: 1, two: 2.0])\n" +
1816+
"assert result.one == 1 && result.two == 2.0\n" +
1817+
"assert result.is(pogo)\n",
1818+
1819+
"Pogo.groovy",
1820+
"class Pogo {\n" +
1821+
" def one, two\n" +
1822+
"}\n",
18191823
};
18201824
//@formatter:on
18211825

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

+133-2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616
package org.eclipse.jdt.groovy.core.tests.xform;
1717

18+
import static org.eclipse.jdt.groovy.core.tests.GroovyBundle.isAtLeastGroovy;
1819
import static org.eclipse.jdt.groovy.core.tests.GroovyBundle.isParrotParser;
1920
import static org.junit.Assume.assumeTrue;
2021

@@ -78,7 +79,8 @@ public void testTypeChecked2() {
7879
"1. ERROR in Main.groovy (at line 5)\n" +
7980
"\tls.add(\'abc\')\n" +
8081
"\t^^^^^^^^^^^^^\n" +
81-
"Groovy:[Static type checking] - Cannot find matching method java.util.ArrayList#add(java.lang.String). Please check if the declared type is correct and if the method exists.\n" +
82+
"Groovy:[Static type checking] - Cannot find matching method java.util.ArrayList#add(java.lang.String)." +
83+
" Please check if the declared type is correct and if the method exists.\n" +
8284
"----------\n");
8385
}
8486

@@ -823,6 +825,45 @@ public void testTypeChecked7363() {
823825
runNegativeTest(sources, "");
824826
}
825827

828+
@Test
829+
public void testTypeChecked7720() {
830+
//@formatter:off
831+
String[] sources = {
832+
"Main.groovy",
833+
"class Consumer<T> {\n" +
834+
" @groovy.transform.TypeChecked\n" +
835+
" def <U> void accept(U param) {\n" +
836+
" T local = param\n" +
837+
" }\n" +
838+
"}\n" +
839+
"class Converter<T, U> {\n" +
840+
" @groovy.transform.TypeChecked\n" +
841+
" U convert(T param) {\n" +
842+
" return param\n" +
843+
" }\n" +
844+
"}\n" +
845+
"null\n",
846+
};
847+
//@formatter:on
848+
849+
if (!isAtLeastGroovy(40)) {
850+
runConformTest(sources);
851+
} else {
852+
runNegativeTest(sources,
853+
"----------\n" +
854+
"1. ERROR in Main.groovy (at line 4)\n" +
855+
"\tT local = param\n" +
856+
"\t ^^^^^\n" +
857+
"Groovy:[Static type checking] - Cannot assign value of type U to variable of type T\n" +
858+
"----------\n" +
859+
"2. ERROR in Main.groovy (at line 10)\n" +
860+
"\treturn param\n" +
861+
"\t ^^^^^\n" +
862+
"Groovy:[Static type checking] - Cannot return value of type T on method returning type U\n" +
863+
"----------\n");
864+
}
865+
}
866+
826867
@Test
827868
public void testTypeChecked7753() {
828869
//@formatter:off
@@ -1856,7 +1897,7 @@ public void testTypeChecked9907() {
18561897

18571898
@Test
18581899
public void testTypeChecked9915() {
1859-
for (String type : new String[] {"List", "Iterable", "Collection"}) {
1900+
for (String type : new String[] {"List", "Collection", "Iterable"}) {
18601901
//@formatter:off
18611902
String[] sources = {
18621903
"Main.groovy",
@@ -1877,6 +1918,24 @@ public void testTypeChecked9915() {
18771918
}
18781919
}
18791920

1921+
@Test
1922+
public void testTypeChecked9915a() {
1923+
for (String type : new String[] {"Set", "Collection", "Iterable"}) {
1924+
//@formatter:off
1925+
String[] sources = {
1926+
"Main.groovy",
1927+
"@groovy.transform.TypeChecked\n" +
1928+
"class C {\n" +
1929+
type + "<String> strings = Collections.emptySet()\n" +
1930+
"}\n" +
1931+
"new C()\n",
1932+
};
1933+
//@formatter:on
1934+
1935+
runConformTest(sources);
1936+
}
1937+
}
1938+
18801939
@Test
18811940
public void testTypeChecked9935() {
18821941
for (String type : new String[] {"def", "int", "Integer", "BigInteger", "BigDecimal"}) {
@@ -2556,6 +2615,34 @@ public void testTypeChecked9998b() {
25562615
runConformTest(sources, "null");
25572616
}
25582617

2618+
@Test
2619+
public void testTypeChecked10002() {
2620+
//@formatter:off
2621+
String[] sources = {
2622+
"Main.groovy",
2623+
"@groovy.transform.TypeChecked\n" +
2624+
"void test() {\n" +
2625+
" List<String> list = ['a','b',3]\n" +
2626+
" Deque<String> deque = ['x','y']\n" +
2627+
"}\n",
2628+
};
2629+
//@formatter:on
2630+
2631+
runNegativeTest(sources,
2632+
"----------\n" +
2633+
"1. ERROR in Main.groovy (at line 3)\n" +
2634+
"\tList<String> list = ['a','b',3]\n" +
2635+
"\t ^^^^^^^^^^^\n" +
2636+
"Groovy:[Static type checking] - Incompatible generic argument types." +
2637+
" Cannot assign java.util.ArrayList<java.io.Serializable<? extends java.lang.Object>> to: java.util.List<java.lang.String>\n" +
2638+
"----------\n" +
2639+
"2. ERROR in Main.groovy (at line 4)\n" +
2640+
"\tDeque<String> deque = ['x','y']\n" +
2641+
"\t^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" +
2642+
"Groovy:[Static type checking] - Cannot assign value of type java.util.List<java.lang.String> to variable of type java.util.Deque<java.lang.String>\n" +
2643+
"----------\n");
2644+
}
2645+
25592646
@Test
25602647
public void testTypeChecked10006() {
25612648
//@formatter:off
@@ -3281,6 +3368,50 @@ public void testTypeChecked10217() {
32813368
runConformTest(sources, "11");
32823369
}
32833370

3371+
@Test
3372+
public void testTypeChecked10220() {
3373+
//@formatter:off
3374+
String[] sources = {
3375+
"Main.groovy",
3376+
"class C<S, T extends Number> {\n" +
3377+
"}\n" +
3378+
"@groovy.transform.TypeChecked\n" +
3379+
"class D<T> {\n" +
3380+
" C<? extends T, Integer> f\n" +
3381+
" D(C<? extends T, Integer> p) {\n" +
3382+
" f = p\n" +
3383+
" }\n" +
3384+
"}\n" +
3385+
"print(new D<String>(null).f)\n",
3386+
};
3387+
//@formatter:on
3388+
3389+
runConformTest(sources, "null");
3390+
}
3391+
3392+
@Test
3393+
public void testTypeChecked10235() {
3394+
if (Float.parseFloat(System.getProperty("java.specification.version")) > 8)
3395+
vmArguments = new String[] {"--add-opens", "java.base/java.util.concurrent=ALL-UNNAMED"};
3396+
3397+
//@formatter:off
3398+
String[] sources = {
3399+
"Main.groovy",
3400+
"@groovy.transform.TypeChecked\n" +
3401+
"void test() {\n" +
3402+
" Set<Integer> integers = java.util.concurrent.ConcurrentHashMap.newKeySet()\n" +
3403+
" printSet(integers)\n" + // Cannot call printSet(Set<Integer>) with arguments [KeySetView<Object,Object>]
3404+
"}\n" +
3405+
"void printSet(Set<Integer> integers) {\n" +
3406+
" println(integers)\n" +
3407+
"}\n" +
3408+
"test()\n",
3409+
};
3410+
//@formatter:on
3411+
3412+
runConformTest(sources, "[]");
3413+
}
3414+
32843415
@Test
32853416
public void testTypeChecked10239() {
32863417
assumeTrue(isParrotParser());

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

+9-2
Original file line numberDiff line numberDiff line change
@@ -984,8 +984,15 @@ && isAssignment(enclosingBinaryExpression.getOperation().getType())) {
984984
if (lType.isUsingGenerics() && missesGenericsTypes(resultType)) {
985985
// the inferred type of the binary expression is the type of the RHS
986986
// "completed" with generics type information available from the LHS
987-
if (!resultType.isGenericsPlaceHolder()) // plain reference loses information
988-
resultType = GenericsUtils.parameterizeType(lType, resultType.getPlainNodeReference());
987+
if (lType.equals(resultType)) {
988+
if (!lType.isGenericsPlaceHolder()) resultType = lType;
989+
} else {
990+
Map<GenericsTypeName, GenericsType> gt = new HashMap<>();
991+
extractGenericsConnections(gt, resultType, resultType.redirect());
992+
extractGenericsConnections(gt, lType, ClassHelper.getNextSuperClass(resultType, lType));
993+
994+
resultType = applyGenericsContext(gt, resultType.redirect());
995+
}
989996
}
990997
// GRECLIPSE end
991998
ClassNode originType = getOriginalDeclarationType(leftExpression);

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

+11-4
Original file line numberDiff line numberDiff line change
@@ -829,8 +829,8 @@ else if (op == LOGICAL_OR) {
829829
typeCheckingContext.secondPassExpressions.add(new SecondPassExpression(expression));
830830
}
831831

832-
boolean isAssignment = isAssignment(expression.getOperation().getType());
833832
/* GRECLIPSE edit -- GROOVY-8974, et al.
833+
boolean isAssignment = isAssignment(expression.getOperation().getType());
834834
if (isAssignment && lType.isUsingGenerics() && missesGenericsTypes(resultType)) {
835835
// unchecked assignment
836836
// examples:
@@ -866,16 +866,23 @@ && isAssignment(enclosingBinaryExpression.getOperation().getType())) {
866866
}
867867

868868
boolean isEmptyDeclaration = (expression instanceof DeclarationExpression && rightExpression instanceof EmptyExpression);
869-
if (isAssignment && !isEmptyDeclaration) {
869+
if (isAssignment(op) && !isEmptyDeclaration) {
870870
if (rightExpression instanceof ConstructorCallExpression) {
871871
inferDiamondType((ConstructorCallExpression) rightExpression, lType);
872872
}
873873
// GRECLIPSE add -- unchecked assignment
874874
if (lType.isUsingGenerics() && missesGenericsTypes(resultType)) {
875875
// the inferred type of the binary expression is the type of the RHS
876876
// "completed" with generics type information available from the LHS
877-
if (!resultType.isGenericsPlaceHolder()) // plain reference loses information
878-
resultType = GenericsUtils.parameterizeType(lType, resultType.getPlainNodeReference());
877+
if (lType.equals(resultType)) {
878+
if (!lType.isGenericsPlaceHolder()) resultType = lType;
879+
} else {
880+
Map<GenericsTypeName, GenericsType> gt = new HashMap<>();
881+
extractGenericsConnections(gt, resultType, resultType.redirect());
882+
extractGenericsConnections(gt, lType, ClassHelper.getNextSuperClass(resultType, lType));
883+
884+
resultType = applyGenericsContext(gt, resultType.redirect());
885+
}
879886
}
880887
// GRECLIPSE end
881888
ClassNode originType = getOriginalDeclarationType(leftExpression);

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

+13
Original file line numberDiff line numberDiff line change
@@ -864,11 +864,24 @@ && isAssignment(enclosingBinaryExpression.getOperation().getType())) {
864864
// List<Type> list = new LinkedList()
865865
// Iterable<Type> iter = new LinkedList()
866866
// Collection<Type> coll = Collections.emptyList()
867+
// Collection<Type> view = ConcurrentHashMap.newKeySet()
867868

868869
// the inferred type of the binary expression is the type of the RHS
869870
// "completed" with generics type information available from the LHS
871+
/* GRECLIPSE edit -- GROOVY-10235
870872
if (!resultType.isGenericsPlaceHolder()) // plain reference drops placeholder
871873
resultType = GenericsUtils.parameterizeType(lType, resultType.getPlainNodeReference());
874+
*/
875+
if (lType.equals(resultType)) {
876+
if (!lType.isGenericsPlaceHolder()) resultType = lType;
877+
} else {
878+
Map<GenericsTypeName, GenericsType> gt = new HashMap<>();
879+
extractGenericsConnections(gt, resultType, resultType.redirect());
880+
extractGenericsConnections(gt, lType, ClassHelper.getNextSuperClass(resultType, lType));
881+
882+
resultType = applyGenericsContext(gt, resultType.redirect());
883+
}
884+
// GRECLIPSE end
872885
}
873886

874887
ClassNode originType = getOriginalDeclarationType(leftExpression);

0 commit comments

Comments
 (0)