From fb0874177a0dfb8b4e76838ff57079fd282e4ed7 Mon Sep 17 00:00:00 2001 From: Eric Milles Date: Wed, 7 Sep 2022 18:34:09 -0500 Subject: [PATCH] GROOVY-8136 --- .../core/tests/xform/TypeCheckedTests.java | 23 ++++++++++++++ .../stc/StaticTypeCheckingVisitor.java | 19 ++++++------ .../stc/StaticTypeCheckingVisitor.java | 31 +++++++------------ .../stc/StaticTypeCheckingVisitor.java | 31 +++++++------------ 4 files changed, 56 insertions(+), 48 deletions(-) diff --git a/base-test/org.eclipse.jdt.groovy.core.tests.compiler/src/org/eclipse/jdt/groovy/core/tests/xform/TypeCheckedTests.java b/base-test/org.eclipse.jdt.groovy.core.tests.compiler/src/org/eclipse/jdt/groovy/core/tests/xform/TypeCheckedTests.java index fa29791f7a..1a476c7953 100644 --- a/base-test/org.eclipse.jdt.groovy.core.tests.compiler/src/org/eclipse/jdt/groovy/core/tests/xform/TypeCheckedTests.java +++ b/base-test/org.eclipse.jdt.groovy.core.tests.compiler/src/org/eclipse/jdt/groovy/core/tests/xform/TypeCheckedTests.java @@ -1750,6 +1750,29 @@ public void testTypeChecked8111() { runConformTest(sources); } + @Test + public void testTypeChecked8136() { + //@formatter:off + String[] sources = { + "Main.groovy", + "interface MVM extends Map> {}\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 diff --git a/base/org.codehaus.groovy25/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java b/base/org.codehaus.groovy25/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java index 600fed9872..b88c08dc28 100644 --- a/base/org.codehaus.groovy25/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java +++ b/base/org.codehaus.groovy25/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java @@ -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; } @@ -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 constructors = node.getDeclaredConstructors(); + List constructors = node.getDeclaredConstructors(); if (constructors.isEmpty() && arguments.length == 0) { return null; } - List constructorList = findMethod(node, "", arguments); - if (constructorList.isEmpty()) { - if (isBeingCompiled(node) && arguments.length == 1 && LINKEDHASHMAP_CLASSNODE.equals(arguments[0])) { + constructors = findMethod(node, "", 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") @@ -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); } /** diff --git a/base/org.codehaus.groovy30/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java b/base/org.codehaus.groovy30/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java index deb633ec0f..abd737e332 100644 --- a/base/org.codehaus.groovy30/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java +++ b/base/org.codehaus.groovy30/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java @@ -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; } @@ -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. @@ -1544,13 +1537,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 constructors = node.getDeclaredConstructors(); + List constructors = node.getDeclaredConstructors(); if (constructors.isEmpty() && arguments.length == 0) { return null; } - List constructorList = findMethod(node, "", arguments); - if (constructorList.isEmpty()) { - if (isBeingCompiled(node) && arguments.length == 1 && LINKEDHASHMAP_CLASSNODE.equals(arguments[0])) { + constructors = findMethod(node, "", 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; @@ -1558,11 +1551,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); } /** diff --git a/base/org.codehaus.groovy40/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java b/base/org.codehaus.groovy40/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java index d2817314b1..e2f6d1f229 100644 --- a/base/org.codehaus.groovy40/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java +++ b/base/org.codehaus.groovy40/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java @@ -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; } @@ -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. @@ -1411,13 +1404,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 constructors = node.getDeclaredConstructors(); + List constructors = node.getDeclaredConstructors(); if (constructors.isEmpty() && arguments.length == 0) { return null; } - List constructorList = findMethod(node, "", arguments); - if (constructorList.isEmpty()) { - if (isBeingCompiled(node) && arguments.length == 1 && LinkedHashMap_TYPE.equals(arguments[0])) { + constructors = findMethod(node, "", 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; @@ -1425,11 +1418,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); } /**