You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by pa...@apache.org on 2020/07/18 07:18:54 UTC
[groovy] branch GROOVY_2_5_X updated: GROOVY-7848: retain generics
of list or map elements (port to 2_5_X)
This is an automated email from the ASF dual-hosted git repository.
paulk pushed a commit to branch GROOVY_2_5_X
in repository https://gitbox.apache.org/repos/asf/groovy.git
The following commit(s) were added to refs/heads/GROOVY_2_5_X by this push:
new 7f43e9e GROOVY-7848: retain generics of list or map elements (port to 2_5_X)
7f43e9e is described below
commit 7f43e9eb71850c53a4dd61ac86e7e004eda1bb20
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Mon Jul 13 09:52:56 2020 -0500
GROOVY-7848: retain generics of list or map elements (port to 2_5_X)
[[1],[2]] should infer as List<List<Integer>>
[1:['a'],2:['b']] should infer as Map<Integer,List<String>>
---
.../java/org/codehaus/groovy/ast/GenericsType.java | 4 +--
.../transform/stc/StaticTypeCheckingVisitor.java | 38 ++++++++++------------
.../groovy/transform/stc/GenericsSTCTest.groovy | 20 +++++++++---
3 files changed, 36 insertions(+), 26 deletions(-)
diff --git a/src/main/java/org/codehaus/groovy/ast/GenericsType.java b/src/main/java/org/codehaus/groovy/ast/GenericsType.java
index 0f4d301..e68dfe0 100644
--- a/src/main/java/org/codehaus/groovy/ast/GenericsType.java
+++ b/src/main/java/org/codehaus/groovy/ast/GenericsType.java
@@ -62,8 +62,8 @@ public class GenericsType extends ASTNode {
return type;
}
- public void setType(ClassNode type) {
- this.type = type;
+ public void setType(final ClassNode type) {
+ this.type = type;
}
public String toString() {
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 6317fa5..1234ce1 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -4889,18 +4889,17 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
protected ClassNode inferListExpressionType(final ListExpression list) {
List<Expression> expressions = list.getExpressions();
- if (expressions.isEmpty()) {
- // cannot infer, return list type
+ int nExpressions = expressions.size();
+ if (nExpressions == 0) {
return list.getType();
}
ClassNode listType = list.getType();
GenericsType[] genericsTypes = listType.getGenericsTypes();
if ((genericsTypes == null
|| genericsTypes.length == 0
- || (genericsTypes.length == 1 && OBJECT_TYPE.equals(genericsTypes[0].getType())))
- && (!expressions.isEmpty())) {
+ || (genericsTypes.length == 1 && OBJECT_TYPE.equals(genericsTypes[0].getType())))) {
// maybe we can infer the component type
- List<ClassNode> nodes = new LinkedList<ClassNode>();
+ List<ClassNode> nodes = new ArrayList<>(nExpressions);
for (Expression expression : expressions) {
if (isNullConstant(expression)) {
// a null element is found in the list, skip it because we'll use the other elements from the list
@@ -4908,14 +4907,12 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
nodes.add(getType(expression));
}
}
- if (nodes.isEmpty()) {
- // every element was the null constant
- return listType;
+ if (!nodes.isEmpty()) {
+ ClassNode itemType = lowestUpperBound(nodes);
+
+ listType = listType.getPlainNodeReference();
+ listType.setGenericsTypes(new GenericsType[]{new GenericsType(wrapTypeIfNecessary(itemType))});
}
- ClassNode superType = getWrapper(lowestUpperBound(nodes)); // to be used in generics, type must be boxed
- ClassNode inferred = listType.getPlainNodeReference();
- inferred.setGenericsTypes(new GenericsType[]{new GenericsType(wrapTypeIfNecessary(superType))});
- return inferred;
}
return listType;
}
@@ -4927,23 +4924,24 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
protected ClassNode inferMapExpressionType(final MapExpression map) {
ClassNode mapType = LINKEDHASHMAP_CLASSNODE.getPlainNodeReference();
List<MapEntryExpression> entryExpressions = map.getMapEntryExpressions();
- if (entryExpressions.isEmpty()) return mapType;
+ int nExpressions = entryExpressions.size();
+ if (nExpressions == 0) return mapType;
+
GenericsType[] genericsTypes = mapType.getGenericsTypes();
if (genericsTypes == null
|| genericsTypes.length < 2
|| (genericsTypes.length == 2 && OBJECT_TYPE.equals(genericsTypes[0].getType()) && OBJECT_TYPE.equals(genericsTypes[1].getType()))) {
- List<ClassNode> keyTypes = new LinkedList<ClassNode>();
- List<ClassNode> valueTypes = new LinkedList<ClassNode>();
+ List<ClassNode> keyTypes = new ArrayList<>(nExpressions);
+ List<ClassNode> valueTypes = new ArrayList<>(nExpressions);
for (MapEntryExpression entryExpression : entryExpressions) {
keyTypes.add(getType(entryExpression.getKeyExpression()));
valueTypes.add(getType(entryExpression.getValueExpression()));
}
- ClassNode keyType = getWrapper(lowestUpperBound(keyTypes)); // to be used in generics, type must be boxed
- ClassNode valueType = getWrapper(lowestUpperBound(valueTypes)); // to be used in generics, type must be boxed
+ ClassNode keyType = lowestUpperBound(keyTypes);
+ ClassNode valueType = lowestUpperBound(valueTypes);
if (!OBJECT_TYPE.equals(keyType) || !OBJECT_TYPE.equals(valueType)) {
- ClassNode inferred = mapType.getPlainNodeReference();
- inferred.setGenericsTypes(new GenericsType[]{new GenericsType(wrapTypeIfNecessary(keyType)), new GenericsType(wrapTypeIfNecessary(valueType))});
- return inferred;
+ mapType = mapType.getPlainNodeReference();
+ mapType.setGenericsTypes(new GenericsType[]{new GenericsType(wrapTypeIfNecessary(keyType)), new GenericsType(wrapTypeIfNecessary(valueType))});
}
}
return mapType;
diff --git a/src/test/groovy/transform/stc/GenericsSTCTest.groovy b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
index 861a8b1..f2d87e7 100644
--- a/src/test/groovy/transform/stc/GenericsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
@@ -1304,8 +1304,8 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
bar()
''', '[Static type checking] - Cannot find matching method Foo#<init>(java.lang.String, int)'
}
-
- // Groovy-5742
+
+ // GROOVY-5742
void testNestedGenerics() {
assertScript '''
import static Next.*
@@ -1322,6 +1322,18 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
'''
}
+ // GROOVY-7848
+ void testNestedGenerics2() {
+ assertScript '''
+ List<Integer> test() {
+ def listOfLists = [[1,2], [3,4]]
+ listOfLists.collect { pair -> pair[0] + pair[1] }
+ }
+ def result = test()
+ assert result == [3,7]
+ '''
+ }
+
void testMethodLevelGenericsFromInterface() {
assertScript '''
interface A {
@@ -1337,8 +1349,8 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
true
'''
}
-
- // Groovy-5610
+
+ // GROOVY-5610
void testMethodWithDefaultArgument() {
assertScript '''
class A{}