Skip to content

Commit fb08741

Browse files
committed
GROOVY-8136
1 parent eff8051 commit fb08741

File tree

4 files changed

+56
-48
lines changed

4 files changed

+56
-48
lines changed

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

+23
Original file line numberDiff line numberDiff line change
@@ -1750,6 +1750,29 @@ public void testTypeChecked8111() {
17501750
runConformTest(sources);
17511751
}
17521752

1753+
@Test
1754+
public void testTypeChecked8136() {
1755+
//@formatter:off
1756+
String[] sources = {
1757+
"Main.groovy",
1758+
"interface MVM<K,V> extends Map<K,List<V>> {}\n" +
1759+
"@groovy.transform.TypeChecked\n" +
1760+
"@SuppressWarnings('rawtypes')\n" +
1761+
"void test() {\n" +
1762+
" MVM m = [:]\n" +
1763+
"}\n",
1764+
};
1765+
//@formatter:on
1766+
1767+
runNegativeTest(sources,
1768+
"----------\n" +
1769+
"1. ERROR in Main.groovy (at line 5)\n" +
1770+
"\tMVM m = [:]\n" +
1771+
"\t ^^^\n" +
1772+
"Groovy:[Static type checking] - No matching constructor found: MVM(java.util.LinkedHashMap)\n" +
1773+
"----------\n");
1774+
}
1775+
17531776
@Test
17541777
public void testTypeChecked8202() {
17551778
//@formatter:off

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

+9-10
Original file line numberDiff line numberDiff line change
@@ -1435,13 +1435,12 @@ && implementsInterfaceOrIsSubclassOf(inferredRightExpressionType, LIST_TYPE)
14351435
}
14361436

14371437
private void addMapAssignmentConstructorErrors(final ClassNode leftRedirect, final Expression leftExpression, final Expression rightExpression) {
1438-
/* GRECLIPSE edit -- GROOVY-6802, GROOVY-6803, et al.
1438+
/* GRECLIPSE edit -- GROOVY-6802, GROOVY-6803, GROOVY-8136, et al.
14391439
if (!(rightExpression instanceof MapExpression) || (leftExpression instanceof VariableExpression && ((VariableExpression) leftExpression).isDynamicTyped())
14401440
|| leftRedirect.equals(OBJECT_TYPE) || implementsInterfaceOrIsSubclassOf(leftRedirect, MAP_TYPE)) {
14411441
*/
1442-
if ((leftExpression instanceof VariableExpression && ((VariableExpression) leftExpression).isDynamicTyped())
1443-
|| (isWildcardLeftHandSide(leftRedirect) && !leftRedirect.equals(CLASS_Type))
1444-
|| implementsInterfaceOrIsSubclassOf(leftRedirect, MAP_TYPE)) {
1442+
if (!isConstructorAbbreviation(leftRedirect, rightExpression)
1443+
|| (isWildcardLeftHandSide(leftRedirect) && !leftRedirect.equals(CLASS_Type))) {
14451444
// GRECLIPSE end
14461445
return;
14471446
}
@@ -1624,13 +1623,13 @@ protected MethodNode checkGroovyStyleConstructor(final ClassNode node, final Cla
16241623
// in that case, we are facing a list constructor assigned to a def or object
16251624
return null;
16261625
}
1627-
List<ConstructorNode> constructors = node.getDeclaredConstructors();
1626+
List<? extends MethodNode> constructors = node.getDeclaredConstructors();
16281627
if (constructors.isEmpty() && arguments.length == 0) {
16291628
return null;
16301629
}
1631-
List<MethodNode> constructorList = findMethod(node, "<init>", arguments);
1632-
if (constructorList.isEmpty()) {
1633-
if (isBeingCompiled(node) && arguments.length == 1 && LINKEDHASHMAP_CLASSNODE.equals(arguments[0])) {
1630+
constructors = findMethod(node, "<init>", arguments);
1631+
if (constructors.isEmpty()) {
1632+
if (isBeingCompiled(node) && !node.isInterface() && arguments.length == 1 && arguments[0].equals(LINKEDHASHMAP_CLASSNODE)) {
16341633
// there will be a default hash map constructor added later
16351634
ConstructorNode cn = new ConstructorNode(Opcodes.ACC_PUBLIC, new Parameter[]{
16361635
new Parameter(LINKEDHASHMAP_CLASSNODE, "args")
@@ -1640,11 +1639,11 @@ protected MethodNode checkGroovyStyleConstructor(final ClassNode node, final Cla
16401639
addStaticTypeError("No matching constructor found: " + prettyPrintTypeName(node) + toMethodParametersString("", arguments), source);
16411640
return null;
16421641
}
1643-
} else if (constructorList.size() > 1) {
1642+
} else if (constructors.size() > 1) {
16441643
addStaticTypeError("Ambiguous constructor call " + prettyPrintTypeName(node) + toMethodParametersString("", arguments), source);
16451644
return null;
16461645
}
1647-
return constructorList.get(0);
1646+
return constructors.get(0);
16481647
}
16491648

16501649
/**

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

+12-19
Original file line numberDiff line numberDiff line change
@@ -1358,9 +1358,15 @@ private void addListAssignmentConstructorErrors(final ClassNode leftRedirect, fi
13581358
}
13591359

13601360
private void addMapAssignmentConstructorErrors(final ClassNode leftRedirect, final Expression leftExpression, final Expression rightExpression) {
1361+
/* GRECLIPSE edit -- GROOVY-8136
13611362
if ((leftExpression instanceof VariableExpression && ((VariableExpression) leftExpression).isDynamicTyped())
13621363
|| (isWildcardLeftHandSide(leftRedirect) && !leftRedirect.equals(CLASS_Type))
13631364
|| implementsInterfaceOrIsSubclassOf(leftRedirect, MAP_TYPE)) {
1365+
*/
1366+
if (!isConstructorAbbreviation(leftRedirect, rightExpression)
1367+
// GROOVY-6802, GROOVY-6803: Object, String or [Bb]oolean target
1368+
|| (isWildcardLeftHandSide(leftRedirect) && !leftRedirect.equals(CLASS_Type))) {
1369+
// GRECLIPSE end
13641370
return;
13651371
}
13661372

@@ -1519,19 +1525,6 @@ protected static boolean hasRHSIncompleteGenericTypeInfo(final ClassNode inferre
15191525
return replaceType;
15201526
}
15211527

1522-
/**
1523-
* Checks that a constructor style expression is valid regarding the number
1524-
* of arguments and the argument types.
1525-
*
1526-
* @param node the class node for which we will try to find a matching constructor
1527-
* @param arguments the constructor arguments
1528-
* @deprecated use {@link #checkGroovyStyleConstructor(org.codehaus.groovy.ast.ClassNode, org.codehaus.groovy.ast.ClassNode[], org.codehaus.groovy.ast.ASTNode)} )}
1529-
*/
1530-
@Deprecated
1531-
protected void checkGroovyStyleConstructor(final ClassNode node, final ClassNode[] arguments) {
1532-
checkGroovyStyleConstructor(node, arguments, typeCheckingContext.getEnclosingClassNode());
1533-
}
1534-
15351528
/**
15361529
* Checks that a constructor style expression is valid regarding the number
15371530
* of arguments and the argument types.
@@ -1544,25 +1537,25 @@ protected MethodNode checkGroovyStyleConstructor(final ClassNode node, final Cla
15441537
// in that case, we are facing a list constructor assigned to a def or object
15451538
return null;
15461539
}
1547-
List<ConstructorNode> constructors = node.getDeclaredConstructors();
1540+
List<? extends MethodNode> constructors = node.getDeclaredConstructors();
15481541
if (constructors.isEmpty() && arguments.length == 0) {
15491542
return null;
15501543
}
1551-
List<MethodNode> constructorList = findMethod(node, "<init>", arguments);
1552-
if (constructorList.isEmpty()) {
1553-
if (isBeingCompiled(node) && arguments.length == 1 && LINKEDHASHMAP_CLASSNODE.equals(arguments[0])) {
1544+
constructors = findMethod(node, "<init>", arguments);
1545+
if (constructors.isEmpty()) {
1546+
if (isBeingCompiled(node) && !node.isInterface() && arguments.length == 1 && arguments[0].equals(LINKEDHASHMAP_CLASSNODE)) {
15541547
// there will be a default hash map constructor added later
15551548
ConstructorNode cn = new ConstructorNode(Opcodes.ACC_PUBLIC, new Parameter[]{new Parameter(LINKEDHASHMAP_CLASSNODE, "args")}, ClassNode.EMPTY_ARRAY, EmptyStatement.INSTANCE);
15561549
return cn;
15571550
} else {
15581551
addStaticTypeError("No matching constructor found: " + prettyPrintTypeName(node) + toMethodParametersString("", arguments), source);
15591552
return null;
15601553
}
1561-
} else if (constructorList.size() > 1) {
1554+
} else if (constructors.size() > 1) {
15621555
addStaticTypeError("Ambiguous constructor call " + prettyPrintTypeName(node) + toMethodParametersString("", arguments), source);
15631556
return null;
15641557
}
1565-
return constructorList.get(0);
1558+
return constructors.get(0);
15661559
}
15671560

15681561
/**

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

+12-19
Original file line numberDiff line numberDiff line change
@@ -1270,9 +1270,15 @@ private void addListAssignmentConstructorErrors(final ClassNode leftRedirect, fi
12701270
}
12711271

12721272
private void addMapAssignmentConstructorErrors(final ClassNode leftRedirect, final Expression leftExpression, final Expression rightExpression) {
1273+
/* GRECLIPSE edit -- GROOVY-8136
12731274
if ((leftExpression instanceof VariableExpression && ((VariableExpression) leftExpression).isDynamicTyped())
12741275
|| (isWildcardLeftHandSide(leftRedirect) && !isClassType(leftRedirect)) // GROOVY-6802, GROOVY-6803
12751276
|| implementsInterfaceOrIsSubclassOf(leftRedirect, MAP_TYPE)) {
1277+
*/
1278+
if (!isConstructorAbbreviation(leftRedirect, rightExpression)
1279+
// GROOVY-6802, GROOVY-6803: Object, String or [Bb]oolean target
1280+
|| (isWildcardLeftHandSide(leftRedirect) && !isClassType(leftRedirect))) {
1281+
// GRECLIPSE end
12761282
return;
12771283
}
12781284

@@ -1386,19 +1392,6 @@ protected static boolean hasRHSIncompleteGenericTypeInfo(final ClassNode inferre
13861392
return replaceType;
13871393
}
13881394

1389-
/**
1390-
* Checks that a constructor style expression is valid regarding the number
1391-
* of arguments and the argument types.
1392-
*
1393-
* @param node the class node for which we will try to find a matching constructor
1394-
* @param arguments the constructor arguments
1395-
* @deprecated use {@link #checkGroovyStyleConstructor(org.codehaus.groovy.ast.ClassNode, org.codehaus.groovy.ast.ClassNode[], org.codehaus.groovy.ast.ASTNode)} )}
1396-
*/
1397-
@Deprecated
1398-
protected void checkGroovyStyleConstructor(final ClassNode node, final ClassNode[] arguments) {
1399-
checkGroovyStyleConstructor(node, arguments, typeCheckingContext.getEnclosingClassNode());
1400-
}
1401-
14021395
/**
14031396
* Checks that a constructor style expression is valid regarding the number
14041397
* of arguments and the argument types.
@@ -1411,25 +1404,25 @@ protected MethodNode checkGroovyStyleConstructor(final ClassNode node, final Cla
14111404
// in that case, we are facing a list constructor assigned to a def or object
14121405
return null;
14131406
}
1414-
List<ConstructorNode> constructors = node.getDeclaredConstructors();
1407+
List<? extends MethodNode> constructors = node.getDeclaredConstructors();
14151408
if (constructors.isEmpty() && arguments.length == 0) {
14161409
return null;
14171410
}
1418-
List<MethodNode> constructorList = findMethod(node, "<init>", arguments);
1419-
if (constructorList.isEmpty()) {
1420-
if (isBeingCompiled(node) && arguments.length == 1 && LinkedHashMap_TYPE.equals(arguments[0])) {
1411+
constructors = findMethod(node, "<init>", arguments);
1412+
if (constructors.isEmpty()) {
1413+
if (isBeingCompiled(node) && !node.isInterface() && arguments.length == 1 && arguments[0].equals(LinkedHashMap_TYPE)) {
14211414
// there will be a default hash map constructor added later
14221415
ConstructorNode cn = new ConstructorNode(Opcodes.ACC_PUBLIC, new Parameter[]{new Parameter(LinkedHashMap_TYPE, "args")}, ClassNode.EMPTY_ARRAY, EmptyStatement.INSTANCE);
14231416
return cn;
14241417
} else {
14251418
addStaticTypeError("No matching constructor found: " + prettyPrintTypeName(node) + toMethodParametersString("", arguments), source);
14261419
return null;
14271420
}
1428-
} else if (constructorList.size() > 1) {
1421+
} else if (constructors.size() > 1) {
14291422
addStaticTypeError("Ambiguous constructor call " + prettyPrintTypeName(node) + toMethodParametersString("", arguments), source);
14301423
return null;
14311424
}
1432-
return constructorList.get(0);
1425+
return constructors.get(0);
14331426
}
14341427

14351428
/**

0 commit comments

Comments
 (0)