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/05/10 18:12:34 UTC
[groovy] branch master updated: GROOVY-10619: STC: handle wildcard for self-referential type parameter
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 c251218394 GROOVY-10619: STC: handle wildcard for self-referential type parameter
c251218394 is described below
commit c2512183947e0657298df384bd88f8add6224d98
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Tue May 10 13:00:35 2022 -0500
GROOVY-10619: STC: handle wildcard for self-referential type parameter
---
.../transform/stc/StaticTypeCheckingSupport.java | 47 ++++++++++++++--------
.../groovy/transform/stc/GenericsSTCTest.groovy | 17 ++++++++
2 files changed, 47 insertions(+), 17 deletions(-)
diff --git a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
index de791072b4..e8ebb62fc5 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
@@ -1936,31 +1936,44 @@ public abstract class StaticTypeCheckingSupport {
if (type.isArray()) {
return boundUnboundedWildcards(type.getComponentType()).makeArray();
}
- ClassNode target = type.redirect();
- if (target == null || type == target || !isUsingGenericsOrIsArrayUsingGenerics(target)) return type;
+ ClassNode redirect = type.redirect();
+ if (redirect == null || redirect == type || !isUsingGenericsOrIsArrayUsingGenerics(redirect)) {
+ return type;
+ }
ClassNode newType = type.getPlainNodeReference();
newType.setGenericsPlaceHolder(type.isGenericsPlaceHolder());
- newType.setGenericsTypes(boundUnboundedWildcards(type.getGenericsTypes(), target.getGenericsTypes()));
+ newType.setGenericsTypes(boundUnboundedWildcards(type.getGenericsTypes(), redirect.getGenericsTypes()));
return newType;
}
- private static GenericsType[] boundUnboundedWildcards(final GenericsType[] usage, final GenericsType[] declaration) {
- GenericsType[] newGts = new GenericsType[usage.length];
- for (int i = 0, n = usage.length; i < n; i += 1) {
- newGts[i] = boundUnboundedWildcard(usage[i], declaration[i]);
+ private static GenericsType[] boundUnboundedWildcards(final GenericsType[] actual, final GenericsType[] declared) {
+ int n = actual.length; GenericsType[] newTypes = new GenericsType[n];
+ for (int i = 0; i < n; i += 1) {
+ newTypes[i] = boundUnboundedWildcard(actual[i], declared[i]);
}
- return newGts;
+ return newTypes;
}
- private static GenericsType boundUnboundedWildcard(final GenericsType gt, final GenericsType spec) {
- if (isUnboundedWildcard(gt)) {
- ClassNode base = makeWithoutCaching("?");
- // The bounds on the declared type are at least as good as the ones on an unbounded wildcard, since it has none!
- GenericsType newGt = new GenericsType(base, spec.getUpperBounds(), spec.getLowerBound());
- newGt.setWildcard(true);
- return newGt;
- }
- return gt;
+ private static GenericsType boundUnboundedWildcard(final GenericsType actual, final GenericsType declared) {
+ if (!isUnboundedWildcard(actual)) return actual;
+ ClassNode lowerBound = declared.getLowerBound();
+ ClassNode[] upperBounds = declared.getUpperBounds();
+ if (lowerBound != null) {
+ assert upperBounds == null;
+ } else if (upperBounds == null) {
+ upperBounds = new ClassNode[]{OBJECT_TYPE};
+ } else if (declared.isPlaceholder()) {
+ upperBounds = upperBounds.clone();
+ for (int i = 0, n = upperBounds.length; i < n; i += 1) {
+ // GROOVY-10055, GROOVY-10619: purge self references
+ if (GenericsUtils.extractPlaceholders(upperBounds[i])
+ .containsKey(new GenericsTypeName(declared.getName())))
+ upperBounds[i] = upperBounds[i].getPlainNodeReference();
+ }
+ }
+ GenericsType newType = new GenericsType(makeWithoutCaching("?"), upperBounds, lowerBound);
+ newType.setWildcard(true);
+ return newType;
}
public static boolean isUnboundedWildcard(final GenericsType gt) {
diff --git a/src/test/groovy/transform/stc/GenericsSTCTest.groovy b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
index 0750e61810..8dc1cff70a 100644
--- a/src/test/groovy/transform/stc/GenericsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
@@ -4480,6 +4480,23 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
'''
}
+ // GROOVY-10619
+ void testSelfReferentialTypeParameter5() {
+ assertScript '''
+ @Grab('org.springframework.boot:spring-boot-starter-webflux:2.6.7')
+ import static org.springframework.http.MediaType.APPLICATION_JSON
+ import org.springframework.core.ParameterizedTypeReference
+
+ List<BigDecimal> test(org.springframework.web.reactive.function.client.WebClient web) {
+ def response = web.get()
+ .uri('/something?id={id}', 'id').accept(APPLICATION_JSON).retrieve()
+ .toEntity(new ParameterizedTypeReference<List<BigDecimal>>() {})
+ .block(java.time.Duration.ofSeconds(2))
+ return response.getBody() ?: []
+ }
+ '''
+ }
+
// GROOVY-7804
void testParameterlessClosureToGenericSAMTypeArgumentCoercion() {
assertScript '''