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/06/30 21:33:32 UTC
[groovy] branch master updated: GROOVY-10651, GROOVY-10671: wildcard implicit bounding
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 03886c5fe8 GROOVY-10651, GROOVY-10671: wildcard implicit bounding
03886c5fe8 is described below
commit 03886c5fe82cb8664da223f8cd82ada2c2c8b3c7
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Thu Jun 30 15:35:25 2022 -0500
GROOVY-10651, GROOVY-10671: wildcard implicit bounding
---
.../codehaus/groovy/ast/tools/GenericsUtils.java | 45 ++++++++++++++++------
.../groovy/transform/stc/GenericsSTCTest.groovy | 12 ++++++
2 files changed, 45 insertions(+), 12 deletions(-)
diff --git a/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java b/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java
index 51275fb1fb..f8d376171c 100644
--- a/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java
+++ b/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java
@@ -130,14 +130,29 @@ public class GenericsUtils {
}
/**
- * Generates a wildcard generic type in order to be used for checks against class nodes.
- * See {@link GenericsType#isCompatibleWith(org.codehaus.groovy.ast.ClassNode)}.
+ * Generates a wildcard generic type with implicit upper and optional lower
+ * bounds. The result provides "?" or "? super T" (no "extends") semantics.
+ */
+ private static GenericsType boundWildcardType(final ClassNode implicit, final ClassNode lower) {
+ ClassNode base = ClassHelper.makeWithoutCaching("?");
+ base.setGenericsPlaceHolder(true);
+ base.setRedirect(implicit);
+
+ GenericsType gt = new GenericsType(base, null, lower);
+ gt.setPlaceholder(false);
+ gt.setWildcard(true);
+ return gt;
+ }
+
+ /**
+ * Generates a wildcard generic type in order to be used for checks against
+ * class nodes. See {@link GenericsType#isCompatibleWith(ClassNode)}.
*
- * @param types the type to be used as the wildcard upper bound
- * @return a wildcard generics type
+ * @param types the type(s) to be used as the wildcard's upper bound
*/
public static GenericsType buildWildcardType(final ClassNode... types) {
ClassNode base = ClassHelper.makeWithoutCaching("?");
+
GenericsType gt = new GenericsType(base, types, null);
gt.setWildcard(true);
return gt;
@@ -170,31 +185,37 @@ public class GenericsUtils {
}
if (!type.isUsingGenerics() || !type.isRedirectNode()) return;
- GenericsType[] parameterized = type.getGenericsTypes(); int n;
- if (parameterized == null || (n = parameterized.length) == 0) return;
+ GenericsType[] genericsTypes = type.getGenericsTypes(); int n;
+ if (genericsTypes == null || (n = genericsTypes.length) == 0) return;
// GROOVY-8609, GROOVY-10067, etc.
if (type.isGenericsPlaceHolder()) {
- GenericsType gt = parameterized[0];
+ GenericsType gt = genericsTypes[0];
placeholders.putIfAbsent(new GenericsType.GenericsTypeName(gt.getName()), gt);
return;
}
GenericsType[] redirectGenericsTypes = type.redirect().getGenericsTypes();
if (redirectGenericsTypes == null) {
- redirectGenericsTypes = parameterized;
+ redirectGenericsTypes = genericsTypes;
} else if (redirectGenericsTypes.length != n) {
throw new GroovyBugError("Expected earlier checking to detect generics parameter arity mismatch" +
"\nExpected: " + type.getName() + toGenericTypesString(redirectGenericsTypes) +
- "\nSupplied: " + type.getName() + toGenericTypesString(parameterized));
+ "\nSupplied: " + type.getName() + toGenericTypesString(genericsTypes));
}
List<GenericsType> typeArguments = new ArrayList<>(n);
for (int i = 0; i < n; i += 1) {
GenericsType rgt = redirectGenericsTypes[i];
- if (rgt.isPlaceholder()) {
- GenericsType typeArgument = parameterized[i];
- placeholders.computeIfAbsent(new GenericsType.GenericsTypeName(rgt.getName()), name -> {
+ if (rgt.isPlaceholder()) { // type parameter
+ GenericsType typeArgument = genericsTypes[i];
+ placeholders.computeIfAbsent(new GenericsType.GenericsTypeName(rgt.getName()), x -> {
+ if (typeArgument.isWildcard() && typeArgument.getUpperBounds() == null) {
+ ClassNode[] implicitBounds = rgt.getUpperBounds();//GROOVY-10651,GROOVY-10671
+ if (implicitBounds != null && !ClassHelper.isObjectType(implicitBounds[0])) {
+ return boundWildcardType(implicitBounds[0],typeArgument.getLowerBound());
+ }
+ }
typeArguments.add(typeArgument);
return typeArgument;
});
diff --git a/src/test/groovy/transform/stc/GenericsSTCTest.groovy b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
index a5762380cf..dd92c842a4 100644
--- a/src/test/groovy/transform/stc/GenericsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
@@ -4824,6 +4824,18 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
'''
}
+ // GROOVY-10671
+ void testAssertJ() {
+ assertScript '''
+ @Grab('org.assertj:assertj-core:3.23.1')
+ import static org.assertj.core.api.Assertions.assertThat
+
+ def strings = (Collection<String>) ['a','b']
+ assertThat(strings).as('assertion description')
+ .containsExactlyInAnyOrderElementsOf(['a','b'])
+ '''
+ }
+
//--------------------------------------------------------------------------
static class MyList