You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by em...@apache.org on 2022/09/07 20:29:59 UTC
[groovy] branch master updated: GROOVY-8136: STC: map literal assignment to interface that extends `Map`
This is an automated email from the ASF dual-hosted git repository.
emilles pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/groovy.git
The following commit(s) were added to refs/heads/master by this push:
new 099cf5b3f0 GROOVY-8136: STC: map literal assignment to interface that extends `Map`
099cf5b3f0 is described below
commit 099cf5b3f0ca61ea5daa72ebcea66ef09a74fd84
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Wed Sep 7 15:17:55 2022 -0500
GROOVY-8136: STC: map literal assignment to interface that extends `Map`
---
.../transform/stc/StaticTypeCheckingVisitor.java | 43 +++++++---------------
.../stc/ArraysAndCollectionsSTCTest.groovy | 29 +++++----------
.../stc/FieldsAndPropertiesSTCTest.groovy | 11 ++++++
3 files changed, 34 insertions(+), 49 deletions(-)
diff --git a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
index 8511cdd36a..f0af7aab95 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -1255,19 +1255,18 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
}
}
- private void addMapAssignmentConstructorErrors(final ClassNode leftRedirect, final Expression leftExpression, final Expression rightExpression) {
- if ((leftExpression instanceof VariableExpression && ((VariableExpression) leftExpression).isDynamicTyped())
- || (isWildcardLeftHandSide(leftRedirect) && !isClassType(leftRedirect)) // GROOVY-6802, GROOVY-6803
- || implementsInterfaceOrIsSubclassOf(leftRedirect, MAP_TYPE)) {
+ private void addMapAssignmentConstructorErrors(final ClassNode leftRedirect, final Expression leftExpression, final MapExpression rightExpression) {
+ if (!isConstructorAbbreviation(leftRedirect, rightExpression)
+ // GROOVY-6802, GROOVY-6803: Object, String or [Bb]oolean target
+ || (isWildcardLeftHandSide(leftRedirect) && !isClassType(leftRedirect))) {
return;
}
// groovy constructor shorthand: A a = [x:2, y:3]
- ClassNode[] argTypes = getArgumentTypes(args(rightExpression));
+ ClassNode[] argTypes = {getType(rightExpression)};
checkGroovyStyleConstructor(leftRedirect, argTypes, rightExpression);
// perform additional type checking on arguments
- MapExpression mapExpression = (MapExpression) rightExpression;
- checkGroovyConstructorMap(leftExpression, leftRedirect, mapExpression);
+ checkGroovyConstructorMap(leftExpression, leftRedirect, rightExpression);
}
private void checkTypeGenerics(final ClassNode leftExpressionType, final ClassNode rightExpressionType, final Expression rightExpression) {
@@ -1319,7 +1318,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
if (rightExpression instanceof ListExpression) {
addListAssignmentConstructorErrors(lTypeRedirect, leftExpressionType, rightExpressionType, rightExpression, assignmentExpression);
} else if (rightExpression instanceof MapExpression) {
- addMapAssignmentConstructorErrors(lTypeRedirect, leftExpression, rightExpression);
+ addMapAssignmentConstructorErrors(lTypeRedirect, leftExpression, (MapExpression)rightExpression);
}
if (!hasGStringStringError(leftExpressionType, rType, rightExpression) && !isConstructorAbbreviation(leftExpressionType, rightExpression)) {
checkTypeGenerics(leftExpressionType, rType, rightExpression);
@@ -1372,19 +1371,6 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
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.
@@ -1397,25 +1383,24 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
// 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;
+ return new ConstructorNode(Opcodes.ACC_PUBLIC, new Parameter[]{new Parameter(LinkedHashMap_TYPE, "args")}, ClassNode.EMPTY_ARRAY, EmptyStatement.INSTANCE);
} 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);
}
/**
diff --git a/src/test/groovy/transform/stc/ArraysAndCollectionsSTCTest.groovy b/src/test/groovy/transform/stc/ArraysAndCollectionsSTCTest.groovy
index d80b4559ad..12319efa81 100644
--- a/src/test/groovy/transform/stc/ArraysAndCollectionsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/ArraysAndCollectionsSTCTest.groovy
@@ -263,14 +263,6 @@ class ArraysAndCollectionsSTCTest extends StaticTypeCheckingTestCase {
'''
}
- void testInferredMapDotProperty() {
- assertScript '''
- def map = [:]
- map['a'] = 1
- map.b = 2
- '''
- }
-
void testInlineMap() {
assertScript '''
Map map = [a:1, b:2]
@@ -769,18 +761,6 @@ class ArraysAndCollectionsSTCTest extends StaticTypeCheckingTestCase {
'''
}
- // GROOVY-5797
- void testShouldAllowExpressionAsMapPropertyKey() {
- assertScript '''
- def m( Map param ) {
- def map = [ tim:4 ]
- map[ param.key ]
- }
-
- assert m( [ key: 'tim' ] ) == 4
- '''
- }
-
// GROOVY-5793
void testShouldNotForceAsTypeWhenListOfNullAssignedToArray() {
assertScript '''
@@ -1098,4 +1078,13 @@ class ArraysAndCollectionsSTCTest extends StaticTypeCheckingTestCase {
''',
'Cannot assign java.util.LinkedHashMap<java.lang.Integer, java.lang.Integer> to: java.util.Map<java.lang.String, java.lang.Integer>'
}
+
+ // GROOVY-8136
+ void testInterfaceThatExtendsMapInitializedByMapLiteral() {
+ shouldFailWithMessages '''
+ interface MVM<K, V> extends Map<K, List<V>> { }
+ MVM map = [:] // no STC error; fails at runtime
+ ''',
+ 'No matching constructor found'
+ }
}
diff --git a/src/test/groovy/transform/stc/FieldsAndPropertiesSTCTest.groovy b/src/test/groovy/transform/stc/FieldsAndPropertiesSTCTest.groovy
index 4f8c904d36..1ea452e4ec 100644
--- a/src/test/groovy/transform/stc/FieldsAndPropertiesSTCTest.groovy
+++ b/src/test/groovy/transform/stc/FieldsAndPropertiesSTCTest.groovy
@@ -589,6 +589,17 @@ class FieldsAndPropertiesSTCTest extends StaticTypeCheckingTestCase {
'''
}
+ // GROOVY-5797
+ void testReadMapProperty2() {
+ assertScript '''
+ def m(Map foo) {
+ def map = [baz: 1]
+ map[ foo.bar ]
+ }
+ assert m(bar:'baz') == 1
+ '''
+ }
+
void testWriteMapProperty() {
assertScript '''
def map = [:]