Skip to content

Commit

Permalink
GROOVY-8136
Browse files Browse the repository at this point in the history
  • Loading branch information
eric-milles committed Sep 7, 2022
1 parent eff8051 commit fb08741
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1750,6 +1750,29 @@ public void testTypeChecked8111() {
runConformTest(sources);
}

@Test
public void testTypeChecked8136() {
//@formatter:off
String[] sources = {
"Main.groovy",
"interface MVM<K,V> extends Map<K,List<V>> {}\n" +
"@groovy.transform.TypeChecked\n" +
"@SuppressWarnings('rawtypes')\n" +
"void test() {\n" +
" MVM m = [:]\n" +
"}\n",
};
//@formatter:on

runNegativeTest(sources,
"----------\n" +
"1. ERROR in Main.groovy (at line 5)\n" +
"\tMVM m = [:]\n" +
"\t ^^^\n" +
"Groovy:[Static type checking] - No matching constructor found: MVM(java.util.LinkedHashMap)\n" +
"----------\n");
}

@Test
public void testTypeChecked8202() {
//@formatter:off
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1435,13 +1435,12 @@ && implementsInterfaceOrIsSubclassOf(inferredRightExpressionType, LIST_TYPE)
}

private void addMapAssignmentConstructorErrors(final ClassNode leftRedirect, final Expression leftExpression, final Expression rightExpression) {
/* GRECLIPSE edit -- GROOVY-6802, GROOVY-6803, et al.
/* GRECLIPSE edit -- GROOVY-6802, GROOVY-6803, GROOVY-8136, et al.
if (!(rightExpression instanceof MapExpression) || (leftExpression instanceof VariableExpression && ((VariableExpression) leftExpression).isDynamicTyped())
|| leftRedirect.equals(OBJECT_TYPE) || implementsInterfaceOrIsSubclassOf(leftRedirect, MAP_TYPE)) {
*/
if ((leftExpression instanceof VariableExpression && ((VariableExpression) leftExpression).isDynamicTyped())
|| (isWildcardLeftHandSide(leftRedirect) && !leftRedirect.equals(CLASS_Type))
|| implementsInterfaceOrIsSubclassOf(leftRedirect, MAP_TYPE)) {
if (!isConstructorAbbreviation(leftRedirect, rightExpression)
|| (isWildcardLeftHandSide(leftRedirect) && !leftRedirect.equals(CLASS_Type))) {
// GRECLIPSE end
return;
}
Expand Down Expand Up @@ -1624,13 +1623,13 @@ protected MethodNode checkGroovyStyleConstructor(final ClassNode node, final Cla
// in that case, we are facing a list constructor assigned to a def or object
return null;
}
List<ConstructorNode> constructors = node.getDeclaredConstructors();
List<? extends MethodNode> constructors = node.getDeclaredConstructors();
if (constructors.isEmpty() && arguments.length == 0) {
return null;
}
List<MethodNode> constructorList = findMethod(node, "<init>", arguments);
if (constructorList.isEmpty()) {
if (isBeingCompiled(node) && arguments.length == 1 && LINKEDHASHMAP_CLASSNODE.equals(arguments[0])) {
constructors = findMethod(node, "<init>", arguments);
if (constructors.isEmpty()) {
if (isBeingCompiled(node) && !node.isInterface() && arguments.length == 1 && arguments[0].equals(LINKEDHASHMAP_CLASSNODE)) {
// there will be a default hash map constructor added later
ConstructorNode cn = new ConstructorNode(Opcodes.ACC_PUBLIC, new Parameter[]{
new Parameter(LINKEDHASHMAP_CLASSNODE, "args")
Expand All @@ -1640,11 +1639,11 @@ protected MethodNode checkGroovyStyleConstructor(final ClassNode node, final Cla
addStaticTypeError("No matching constructor found: " + prettyPrintTypeName(node) + toMethodParametersString("", arguments), source);
return null;
}
} else if (constructorList.size() > 1) {
} else if (constructors.size() > 1) {
addStaticTypeError("Ambiguous constructor call " + prettyPrintTypeName(node) + toMethodParametersString("", arguments), source);
return null;
}
return constructorList.get(0);
return constructors.get(0);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1358,9 +1358,15 @@ private void addListAssignmentConstructorErrors(final ClassNode leftRedirect, fi
}

private void addMapAssignmentConstructorErrors(final ClassNode leftRedirect, final Expression leftExpression, final Expression rightExpression) {
/* GRECLIPSE edit -- GROOVY-8136
if ((leftExpression instanceof VariableExpression && ((VariableExpression) leftExpression).isDynamicTyped())
|| (isWildcardLeftHandSide(leftRedirect) && !leftRedirect.equals(CLASS_Type))
|| implementsInterfaceOrIsSubclassOf(leftRedirect, MAP_TYPE)) {
*/
if (!isConstructorAbbreviation(leftRedirect, rightExpression)
// GROOVY-6802, GROOVY-6803: Object, String or [Bb]oolean target
|| (isWildcardLeftHandSide(leftRedirect) && !leftRedirect.equals(CLASS_Type))) {
// GRECLIPSE end
return;
}

Expand Down Expand Up @@ -1519,19 +1525,6 @@ protected static boolean hasRHSIncompleteGenericTypeInfo(final ClassNode inferre
return replaceType;
}

/**
* Checks that a constructor style expression is valid regarding the number
* of arguments and the argument types.
*
* @param node the class node for which we will try to find a matching constructor
* @param arguments the constructor arguments
* @deprecated use {@link #checkGroovyStyleConstructor(org.codehaus.groovy.ast.ClassNode, org.codehaus.groovy.ast.ClassNode[], org.codehaus.groovy.ast.ASTNode)} )}
*/
@Deprecated
protected void checkGroovyStyleConstructor(final ClassNode node, final ClassNode[] arguments) {
checkGroovyStyleConstructor(node, arguments, typeCheckingContext.getEnclosingClassNode());
}

/**
* Checks that a constructor style expression is valid regarding the number
* of arguments and the argument types.
Expand All @@ -1544,25 +1537,25 @@ protected MethodNode checkGroovyStyleConstructor(final ClassNode node, final Cla
// in that case, we are facing a list constructor assigned to a def or object
return null;
}
List<ConstructorNode> constructors = node.getDeclaredConstructors();
List<? extends MethodNode> constructors = node.getDeclaredConstructors();
if (constructors.isEmpty() && arguments.length == 0) {
return null;
}
List<MethodNode> constructorList = findMethod(node, "<init>", arguments);
if (constructorList.isEmpty()) {
if (isBeingCompiled(node) && arguments.length == 1 && LINKEDHASHMAP_CLASSNODE.equals(arguments[0])) {
constructors = findMethod(node, "<init>", arguments);
if (constructors.isEmpty()) {
if (isBeingCompiled(node) && !node.isInterface() && arguments.length == 1 && arguments[0].equals(LINKEDHASHMAP_CLASSNODE)) {
// there will be a default hash map constructor added later
ConstructorNode cn = new ConstructorNode(Opcodes.ACC_PUBLIC, new Parameter[]{new Parameter(LINKEDHASHMAP_CLASSNODE, "args")}, ClassNode.EMPTY_ARRAY, EmptyStatement.INSTANCE);
return cn;
} else {
addStaticTypeError("No matching constructor found: " + prettyPrintTypeName(node) + toMethodParametersString("", arguments), source);
return null;
}
} else if (constructorList.size() > 1) {
} else if (constructors.size() > 1) {
addStaticTypeError("Ambiguous constructor call " + prettyPrintTypeName(node) + toMethodParametersString("", arguments), source);
return null;
}
return constructorList.get(0);
return constructors.get(0);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1270,9 +1270,15 @@ private void addListAssignmentConstructorErrors(final ClassNode leftRedirect, fi
}

private void addMapAssignmentConstructorErrors(final ClassNode leftRedirect, final Expression leftExpression, final Expression rightExpression) {
/* GRECLIPSE edit -- GROOVY-8136
if ((leftExpression instanceof VariableExpression && ((VariableExpression) leftExpression).isDynamicTyped())
|| (isWildcardLeftHandSide(leftRedirect) && !isClassType(leftRedirect)) // GROOVY-6802, GROOVY-6803
|| implementsInterfaceOrIsSubclassOf(leftRedirect, MAP_TYPE)) {
*/
if (!isConstructorAbbreviation(leftRedirect, rightExpression)
// GROOVY-6802, GROOVY-6803: Object, String or [Bb]oolean target
|| (isWildcardLeftHandSide(leftRedirect) && !isClassType(leftRedirect))) {
// GRECLIPSE end
return;
}

Expand Down Expand Up @@ -1386,19 +1392,6 @@ protected static boolean hasRHSIncompleteGenericTypeInfo(final ClassNode inferre
return replaceType;
}

/**
* Checks that a constructor style expression is valid regarding the number
* of arguments and the argument types.
*
* @param node the class node for which we will try to find a matching constructor
* @param arguments the constructor arguments
* @deprecated use {@link #checkGroovyStyleConstructor(org.codehaus.groovy.ast.ClassNode, org.codehaus.groovy.ast.ClassNode[], org.codehaus.groovy.ast.ASTNode)} )}
*/
@Deprecated
protected void checkGroovyStyleConstructor(final ClassNode node, final ClassNode[] arguments) {
checkGroovyStyleConstructor(node, arguments, typeCheckingContext.getEnclosingClassNode());
}

/**
* Checks that a constructor style expression is valid regarding the number
* of arguments and the argument types.
Expand All @@ -1411,25 +1404,25 @@ protected MethodNode checkGroovyStyleConstructor(final ClassNode node, final Cla
// in that case, we are facing a list constructor assigned to a def or object
return null;
}
List<ConstructorNode> constructors = node.getDeclaredConstructors();
List<? extends MethodNode> constructors = node.getDeclaredConstructors();
if (constructors.isEmpty() && arguments.length == 0) {
return null;
}
List<MethodNode> constructorList = findMethod(node, "<init>", arguments);
if (constructorList.isEmpty()) {
if (isBeingCompiled(node) && arguments.length == 1 && LinkedHashMap_TYPE.equals(arguments[0])) {
constructors = findMethod(node, "<init>", arguments);
if (constructors.isEmpty()) {
if (isBeingCompiled(node) && !node.isInterface() && arguments.length == 1 && arguments[0].equals(LinkedHashMap_TYPE)) {
// there will be a default hash map constructor added later
ConstructorNode cn = new ConstructorNode(Opcodes.ACC_PUBLIC, new Parameter[]{new Parameter(LinkedHashMap_TYPE, "args")}, ClassNode.EMPTY_ARRAY, EmptyStatement.INSTANCE);
return cn;
} else {
addStaticTypeError("No matching constructor found: " + prettyPrintTypeName(node) + toMethodParametersString("", arguments), source);
return null;
}
} else if (constructorList.size() > 1) {
} else if (constructors.size() > 1) {
addStaticTypeError("Ambiguous constructor call " + prettyPrintTypeName(node) + toMethodParametersString("", arguments), source);
return null;
}
return constructorList.get(0);
return constructors.get(0);
}

/**
Expand Down

0 comments on commit fb08741

Please sign in to comment.