Skip to content

Commit 5cdfa55

Browse files
committed
GROOVY-6802, GROOVY-6803
1 parent 90b5b74 commit 5cdfa55

File tree

4 files changed

+136
-46
lines changed

4 files changed

+136
-46
lines changed

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

+90-25
Original file line numberDiff line numberDiff line change
@@ -637,6 +637,31 @@ public void testCompileStatic23() {
637637
runConformTest(sources, "hello world");
638638
}
639639

640+
@Test // https://github.com/groovy/groovy-eclipse/issues/1191
641+
public void testCompileStatic24() {
642+
assumeTrue(isParrotParser());
643+
644+
//@formatter:off
645+
String[] sources = {
646+
"Main.groovy",
647+
"void m(java.util.function.Function<String, Integer> f) {\n" +
648+
"}\n" +
649+
"@groovy.transform.CompileStatic\n" +
650+
"void test() {\n" +
651+
" m(Object::sleep)\n" + // NPE while processing Main.groovy
652+
"}\n",
653+
};
654+
//@formatter:on
655+
656+
runNegativeTest(sources,
657+
"----------\n" +
658+
"1. ERROR in Main.groovy (at line 5)\n" +
659+
"\tm(Object::sleep)\n" +
660+
"\t ^^^^^^^^^^^^^\n" +
661+
"Groovy:Failed to find the expected method[sleep(java.lang.String)] in the type[java.lang.Object]\n" +
662+
"----------\n");
663+
}
664+
640665
@Test
641666
public void testCompileStatic1505() {
642667
//@formatter:off
@@ -732,31 +757,6 @@ public void testCompileStatic1521() {
732757
runNegativeTest(sources, "");
733758
}
734759

735-
@Test
736-
public void testCompileStatic1191() {
737-
assumeTrue(isParrotParser());
738-
739-
//@formatter:off
740-
String[] sources = {
741-
"Main.groovy",
742-
"void m(java.util.function.Function<String, Integer> f) {\n" +
743-
"}\n" +
744-
"@groovy.transform.CompileStatic\n" +
745-
"void test() {\n" +
746-
" m(Object::sleep)\n" + // NPE while processing Main.groovy
747-
"}\n",
748-
};
749-
//@formatter:on
750-
751-
runNegativeTest(sources,
752-
"----------\n" +
753-
"1. ERROR in Main.groovy (at line 5)\n" +
754-
"\tm(Object::sleep)\n" +
755-
"\t ^^^^^^^^^^^^^\n" +
756-
"Groovy:Failed to find the expected method[sleep(java.lang.String)] in the type[java.lang.Object]\n" +
757-
"----------\n");
758-
}
759-
760760
@Test
761761
public void testCompileStatic6095() {
762762
//@formatter:off
@@ -852,6 +852,71 @@ public void testCompileStatic6782() {
852852
runConformTest(sources);
853853
}
854854

855+
@Test
856+
public void testCompileStatic6802() {
857+
//@formatter:off
858+
String[] sources = {
859+
"Main.groovy",
860+
"@groovy.transform.CompileStatic\n" +
861+
"void test() {\n" +
862+
" Boolean b = [false]\n" +
863+
" print b\n" +
864+
" b = [true];\n" +
865+
" print b\n" +
866+
" b = [];\n" +
867+
" print b\n" +
868+
" b = [:]\n" +
869+
" print b\n" +
870+
"}\n" +
871+
"test()\n",
872+
};
873+
//@formatter:on
874+
875+
runConformTest(sources, "truetruefalsefalse");
876+
}
877+
878+
@Test
879+
public void testCompileStatic6802a() {
880+
//@formatter:off
881+
String[] sources = {
882+
"Main.groovy",
883+
"@groovy.transform.CompileStatic\n" +
884+
"void test() {\n" +
885+
" Class<?> c = []\n" +
886+
"}\n",
887+
};
888+
//@formatter:on
889+
890+
runNegativeTest(sources,
891+
"----------\n" +
892+
"1. ERROR in Main.groovy (at line 3)\n" +
893+
"\tClass<?> c = []\n" +
894+
"\t^^^^^^^^^^^^^^^\n" +
895+
"Groovy:[Static type checking] - No matching constructor found: java.lang.Class()\n" +
896+
"----------\n");
897+
}
898+
899+
@Test
900+
public void testCompileStatic6803() {
901+
//@formatter:off
902+
String[] sources = {
903+
"Main.groovy",
904+
"@groovy.transform.CompileStatic\n" +
905+
"void test() {\n" +
906+
" String s = ['foo']\n" +
907+
" print s\n" +
908+
" s = [];\n" +
909+
" print s\n" +
910+
" s = [:]\n" +
911+
" print s\n" +
912+
"}\n" +
913+
"test()\n",
914+
};
915+
//@formatter:on
916+
917+
runConformTest(sources, "[foo][]" + (isAtLeastGroovy(40) ? "[:]" : "{}"));
918+
}
919+
855920
@Test
856921
public void testCompileStatic6851() {
857922
//@formatter:off

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

+18-7
Original file line numberDiff line numberDiff line change
@@ -1441,7 +1441,7 @@ private void addListAssignmentConstructorErrors(
14411441
// if left type is not a list but right type is a list, then we're in the case of a groovy
14421442
// constructor type : Dimension d = [100,200]
14431443
// In that case, more checks can be performed
1444-
/* GRECLIPSE edit
1444+
/* GRECLIPSE edit -- GROOVY-6802, GROOVY-6803, et al.
14451445
if (rightExpression instanceof ListExpression && !implementsInterfaceOrIsSubclassOf(LIST_TYPE, leftRedirect)) {
14461446
ArgumentListExpression argList = args(((ListExpression) rightExpression).getExpressions());
14471447
ClassNode[] args = getArgumentTypes(argList);
@@ -1457,17 +1457,18 @@ && implementsInterfaceOrIsSubclassOf(inferredRightExpressionType, LIST_TYPE)
14571457
}
14581458
}
14591459
*/
1460+
if (isWildcardLeftHandSide(leftRedirect) && !leftRedirect.equals(CLASS_Type)) return;
1461+
14601462
if (!implementsInterfaceOrIsSubclassOf(LIST_TYPE, leftRedirect)
1461-
&& (!leftRedirect.isAbstract() || leftRedirect.isArray()) && !leftRedirect.equals(OBJECT_TYPE)
1463+
&& (!leftRedirect.isAbstract() || leftRedirect.isArray())
14621464
&& !ArrayList_TYPE.isDerivedFrom(leftRedirect) && !LinkedHashSet_TYPE.isDerivedFrom(leftRedirect)) {
14631465
ClassNode[] types = getArgumentTypes(args(((ListExpression) rightExpression).getExpressions()));
14641466
MethodNode methodNode = checkGroovyStyleConstructor(leftRedirect, types, assignmentExpression);
14651467
if (methodNode != null) {
14661468
rightExpression.putNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET, methodNode);
14671469
}
14681470
} else if (implementsInterfaceOrIsSubclassOf(inferredRightExpressionType, LIST_TYPE)
1469-
&& !implementsInterfaceOrIsSubclassOf(inferredRightExpressionType, leftRedirect)
1470-
&& !isWildcardLeftHandSide(leftRedirect)) {
1471+
&& !implementsInterfaceOrIsSubclassOf(inferredRightExpressionType, leftRedirect)) {
14711472
if (!extension.handleIncompatibleAssignment(leftExpressionType, inferredRightExpressionType, assignmentExpression)) {
14721473
addAssignmentError(leftExpressionType, inferredRightExpressionType, assignmentExpression);
14731474
}
@@ -1476,8 +1477,14 @@ && implementsInterfaceOrIsSubclassOf(inferredRightExpressionType, LIST_TYPE)
14761477
}
14771478

14781479
private void addMapAssignmentConstructorErrors(final ClassNode leftRedirect, final Expression leftExpression, final Expression rightExpression) {
1479-
if (/* GRECLIPSE edit !(rightExpression instanceof MapExpression) || */(leftExpression instanceof VariableExpression && ((VariableExpression) leftExpression).isDynamicTyped())
1480+
/* GRECLIPSE edit -- GROOVY-6802, GROOVY-6803, et al.
1481+
if (!(rightExpression instanceof MapExpression) || (leftExpression instanceof VariableExpression && ((VariableExpression) leftExpression).isDynamicTyped())
14801482
|| leftRedirect.equals(OBJECT_TYPE) || implementsInterfaceOrIsSubclassOf(leftRedirect, MAP_TYPE)) {
1483+
*/
1484+
if ((leftExpression instanceof VariableExpression && ((VariableExpression) leftExpression).isDynamicTyped())
1485+
|| (isWildcardLeftHandSide(leftRedirect) && !leftRedirect.equals(CLASS_Type))
1486+
|| implementsInterfaceOrIsSubclassOf(leftRedirect, MAP_TYPE)) {
1487+
// GRECLIPSE end
14811488
return;
14821489
}
14831490

@@ -1682,11 +1689,11 @@ protected MethodNode checkGroovyStyleConstructor(final ClassNode node, final Cla
16821689
}, ClassNode.EMPTY_ARRAY, EmptyStatement.INSTANCE);
16831690
return cn;
16841691
} else {
1685-
addStaticTypeError("No matching constructor found: " + node + toMethodParametersString("<init>", arguments), source);
1692+
addStaticTypeError("No matching constructor found: " + prettyPrintTypeName(node) + toMethodParametersString("", arguments), source);
16861693
return null;
16871694
}
16881695
} else if (constructorList.size() > 1) {
1689-
addStaticTypeError("Ambiguous constructor call " + node + toMethodParametersString("<init>", arguments), source);
1696+
addStaticTypeError("Ambiguous constructor call " + prettyPrintTypeName(node) + toMethodParametersString("", arguments), source);
16901697
return null;
16911698
}
16921699
return constructorList.get(0);
@@ -5695,7 +5702,11 @@ protected List<MethodNode> findMethod(ClassNode receiver, final String name, fin
56955702
}
56965703
}
56975704

5705+
/* GRECLIPSE edit -- GROOVY-6802, GROOVY-6803
56985706
if (receiver.equals(CLASS_Type) && receiver.getGenericsTypes() != null) {
5707+
*/
5708+
if (isClassClassNodeWrappingConcreteType(receiver)) {
5709+
// GRECLIPSE end
56995710
chosen = findMethod(receiver.getGenericsTypes()[0].getType(), name, args);
57005711
if (!chosen.isEmpty()) return chosen;
57015712
}

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

+18-7
Original file line numberDiff line numberDiff line change
@@ -1366,7 +1366,7 @@ private void addListAssignmentConstructorErrors(final ClassNode leftRedirect, fi
13661366
// if left type is not a list but right type is a list, then we're in the case of a groovy
13671367
// constructor type : Dimension d = [100,200]
13681368
// In that case, more checks can be performed
1369-
/* GRECLIPSE edit
1369+
/* GRECLIPSE edit -- GROOVY-6802, GROOVY-6803, et al.
13701370
if (rightExpression instanceof ListExpression && !implementsInterfaceOrIsSubclassOf(LIST_TYPE, leftRedirect)) {
13711371
ArgumentListExpression argList = args(((ListExpression) rightExpression).getExpressions());
13721372
ClassNode[] args = getArgumentTypes(argList);
@@ -1382,17 +1382,18 @@ && implementsInterfaceOrIsSubclassOf(inferredRightExpressionType, LIST_TYPE)
13821382
}
13831383
}
13841384
*/
1385+
if (isWildcardLeftHandSide(leftRedirect) && !leftRedirect.equals(CLASS_Type)) return;
1386+
13851387
if (!implementsInterfaceOrIsSubclassOf(LIST_TYPE, leftRedirect)
1386-
&& (!leftRedirect.isAbstract() || leftRedirect.isArray()) && !leftRedirect.equals(OBJECT_TYPE)
1388+
&& (!leftRedirect.isAbstract() || leftRedirect.isArray())
13871389
&& !ArrayList_TYPE.isDerivedFrom(leftRedirect) && !LinkedHashSet_TYPE.isDerivedFrom(leftRedirect)) {
13881390
ClassNode[] types = getArgumentTypes(args(((ListExpression) rightExpression).getExpressions()));
13891391
MethodNode methodNode = checkGroovyStyleConstructor(leftRedirect, types, assignmentExpression);
13901392
if (methodNode != null) {
13911393
rightExpression.putNodeMetaData(DIRECT_METHOD_CALL_TARGET, methodNode);
13921394
}
13931395
} else if (implementsInterfaceOrIsSubclassOf(inferredRightExpressionType, LIST_TYPE)
1394-
&& !implementsInterfaceOrIsSubclassOf(inferredRightExpressionType, leftRedirect)
1395-
&& !isWildcardLeftHandSide(leftRedirect)) {
1396+
&& !implementsInterfaceOrIsSubclassOf(inferredRightExpressionType, leftRedirect)) {
13961397
if (!extension.handleIncompatibleAssignment(leftExpressionType, inferredRightExpressionType, assignmentExpression)) {
13971398
addAssignmentError(leftExpressionType, inferredRightExpressionType, assignmentExpression);
13981399
}
@@ -1401,8 +1402,14 @@ && implementsInterfaceOrIsSubclassOf(inferredRightExpressionType, LIST_TYPE)
14011402
}
14021403

14031404
private void addMapAssignmentConstructorErrors(final ClassNode leftRedirect, final Expression leftExpression, final Expression rightExpression) {
1404-
if (/* GRECLIPSE edit !(rightExpression instanceof MapExpression) || */(leftExpression instanceof VariableExpression && ((VariableExpression) leftExpression).isDynamicTyped())
1405+
/* GRECLIPSE edit -- GROOVY-6802, GROOVY-6803, et al.
1406+
if (!(rightExpression instanceof MapExpression) || (leftExpression instanceof VariableExpression && ((VariableExpression) leftExpression).isDynamicTyped())
14051407
|| leftRedirect.equals(OBJECT_TYPE) || implementsInterfaceOrIsSubclassOf(leftRedirect, MAP_TYPE)) {
1408+
*/
1409+
if ((leftExpression instanceof VariableExpression && ((VariableExpression) leftExpression).isDynamicTyped())
1410+
|| (isWildcardLeftHandSide(leftRedirect) && !leftRedirect.equals(CLASS_Type))
1411+
|| implementsInterfaceOrIsSubclassOf(leftRedirect, MAP_TYPE)) {
1412+
// GRECLIPSE end
14061413
return;
14071414
}
14081415

@@ -1594,11 +1601,11 @@ protected MethodNode checkGroovyStyleConstructor(final ClassNode node, final Cla
15941601
ConstructorNode cn = new ConstructorNode(Opcodes.ACC_PUBLIC, new Parameter[]{new Parameter(LINKEDHASHMAP_CLASSNODE, "args")}, ClassNode.EMPTY_ARRAY, EmptyStatement.INSTANCE);
15951602
return cn;
15961603
} else {
1597-
addStaticTypeError("No matching constructor found: " + node + toMethodParametersString("<init>", arguments), source);
1604+
addStaticTypeError("No matching constructor found: " + prettyPrintTypeName(node) + toMethodParametersString("", arguments), source);
15981605
return null;
15991606
}
16001607
} else if (constructorList.size() > 1) {
1601-
addStaticTypeError("Ambiguous constructor call " + node + toMethodParametersString("<init>", arguments), source);
1608+
addStaticTypeError("Ambiguous constructor call " + prettyPrintTypeName(node) + toMethodParametersString("", arguments), source);
16021609
return null;
16031610
}
16041611
return constructorList.get(0);
@@ -5364,7 +5371,11 @@ protected List<MethodNode> findMethod(ClassNode receiver, final String name, fin
53645371
}
53655372
}
53665373

5374+
/* GRECLIPSE edit -- GROOVY-6802, GROOVY-6803
53675375
if (receiver.equals(CLASS_Type) && receiver.getGenericsTypes() != null) {
5376+
*/
5377+
if (isClassClassNodeWrappingConcreteType(receiver)) {
5378+
// GRECLIPSE end
53685379
chosen = findMethod(receiver.getGenericsTypes()[0].getType(), name, args);
53695380
if (!chosen.isEmpty()) return chosen;
53705381
}

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

+10-7
Original file line numberDiff line numberDiff line change
@@ -1254,20 +1254,22 @@ private void addPrecisionErrors(final ClassNode leftRedirect, final ClassNode lh
12541254
}
12551255

12561256
private void addListAssignmentConstructorErrors(final ClassNode leftRedirect, final ClassNode leftExpressionType, final ClassNode inferredRightExpressionType, final Expression rightExpression, final Expression assignmentExpression) {
1257+
// GRECLIPSE add -- GROOVY-6802, GROOVY-6803
1258+
if (isWildcardLeftHandSide(leftRedirect) && !isClassType(leftRedirect)) return;
1259+
// GRECLIPSE end
12571260
// if left type is not a list but right type is a list, then we're in the case of a groovy
12581261
// constructor type : Dimension d = [100,200]
12591262
// In that case, more checks can be performed
12601263
if (!implementsInterfaceOrIsSubclassOf(LIST_TYPE, leftRedirect)
1261-
&& (!leftRedirect.isAbstract() || leftRedirect.isArray()) && !isObjectType(leftRedirect)
1264+
&& (!leftRedirect.isAbstract() || leftRedirect.isArray())
12621265
&& !ArrayList_TYPE.isDerivedFrom(leftRedirect) && !LinkedHashSet_TYPE.isDerivedFrom(leftRedirect)) {
12631266
ClassNode[] types = getArgumentTypes(args(((ListExpression) rightExpression).getExpressions()));
12641267
MethodNode methodNode = checkGroovyStyleConstructor(leftRedirect, types, assignmentExpression);
12651268
if (methodNode != null) {
12661269
rightExpression.putNodeMetaData(DIRECT_METHOD_CALL_TARGET, methodNode);
12671270
}
12681271
} else if (implementsInterfaceOrIsSubclassOf(inferredRightExpressionType, LIST_TYPE)
1269-
&& !implementsInterfaceOrIsSubclassOf(inferredRightExpressionType, leftRedirect)
1270-
&& !isWildcardLeftHandSide(leftRedirect)) {
1272+
&& !implementsInterfaceOrIsSubclassOf(inferredRightExpressionType, leftRedirect)) {
12711273
if (!extension.handleIncompatibleAssignment(leftExpressionType, inferredRightExpressionType, assignmentExpression)) {
12721274
addAssignmentError(leftExpressionType, inferredRightExpressionType, assignmentExpression);
12731275
}
@@ -1276,7 +1278,8 @@ private void addListAssignmentConstructorErrors(final ClassNode leftRedirect, fi
12761278

12771279
private void addMapAssignmentConstructorErrors(final ClassNode leftRedirect, final Expression leftExpression, final Expression rightExpression) {
12781280
if ((leftExpression instanceof VariableExpression && ((VariableExpression) leftExpression).isDynamicTyped())
1279-
|| isObjectType(leftRedirect) || implementsInterfaceOrIsSubclassOf(leftRedirect, MAP_TYPE)) {
1281+
|| (isWildcardLeftHandSide(leftRedirect) && !isClassType(leftRedirect)) // GROOVY-6802, GROOVY-6803
1282+
|| implementsInterfaceOrIsSubclassOf(leftRedirect, MAP_TYPE)) {
12801283
return;
12811284
}
12821285

@@ -1440,11 +1443,11 @@ protected MethodNode checkGroovyStyleConstructor(final ClassNode node, final Cla
14401443
ConstructorNode cn = new ConstructorNode(Opcodes.ACC_PUBLIC, new Parameter[]{new Parameter(LinkedHashMap_TYPE, "args")}, ClassNode.EMPTY_ARRAY, EmptyStatement.INSTANCE);
14411444
return cn;
14421445
} else {
1443-
addStaticTypeError("No matching constructor found: " + node + toMethodParametersString("<init>", arguments), source);
1446+
addStaticTypeError("No matching constructor found: " + prettyPrintTypeName(node) + toMethodParametersString("", arguments), source);
14441447
return null;
14451448
}
14461449
} else if (constructorList.size() > 1) {
1447-
addStaticTypeError("Ambiguous constructor call " + node + toMethodParametersString("<init>", arguments), source);
1450+
addStaticTypeError("Ambiguous constructor call " + prettyPrintTypeName(node) + toMethodParametersString("", arguments), source);
14481451
return null;
14491452
}
14501453
return constructorList.get(0);
@@ -5078,7 +5081,7 @@ protected List<MethodNode> findMethod(ClassNode receiver, final String name, fin
50785081
}
50795082
}
50805083

5081-
if (isClassType(receiver) && receiver.getGenericsTypes() != null) {
5084+
if (isClassClassNodeWrappingConcreteType(receiver)) { // GROOVY-6802, GROOVY-6803
50825085
List<MethodNode> result = findMethod(receiver.getGenericsTypes()[0].getType(), name, args);
50835086
if (!result.isEmpty()) return result;
50845087
}

0 commit comments

Comments
 (0)