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/09/20 00:55:42 UTC
[groovy] branch GROOVY_3_0_X updated: GROOVY-9735: connect
placeholder from context with method generic params
This is an automated email from the ASF dual-hosted git repository.
paulk pushed a commit to branch GROOVY_3_0_X
in repository https://gitbox.apache.org/repos/asf/groovy.git
The following commit(s) were added to refs/heads/GROOVY_3_0_X by this push:
new 1db8a3c GROOVY-9735: connect placeholder from context with method generic params
1db8a3c is described below
commit 1db8a3c23b3f7bc619ba46c6433017cfe84ff6bc
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Sun Sep 13 16:17:34 2020 -0500
GROOVY-9735: connect placeholder from context with method generic params
@groovy.transform.TypeChecked
class C<T extends Number> {
List<T> list
def test() {
m(list) { /*...*/ } // "it" should infer as T/Number
}
def <U> void m(Iterable<U> items,
@ClosureParams(FirstParam.FirstGenericType) Closure block) {
}
}
closes #1363
---
.../codehaus/groovy/ast/tools/GenericsUtils.java | 68 ++++++++++++++--------
.../transform/stc/StaticTypeCheckingSupport.java | 15 +++--
.../transform/stc/StaticTypeCheckingVisitor.java | 10 ++--
.../stc/ClosureParamTypeInferenceSTCTest.groovy | 33 ++++++++++-
4 files changed, 89 insertions(+), 37 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 15a8413..7186af0 100644
--- a/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java
+++ b/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java
@@ -55,7 +55,6 @@ import java.util.function.Predicate;
import static groovy.lang.Tuple.tuple;
import static org.apache.groovy.util.SystemUtil.getSystemPropertySafe;
import static org.codehaus.groovy.runtime.DefaultGroovyMethods.plus;
-import static org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.getCorrectedClassNode;
import static org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.implementsInterfaceOrIsSubclassOf;
/**
@@ -514,12 +513,10 @@ public class GenericsUtils {
extractSuperClassGenerics(type.getGenericsTypes(), target.getGenericsTypes(), spec);
}
} else {
- // have first to find matching super class or interface
+ // find matching super class or interface
ClassNode superClass = getSuperClass(type, target);
-
if (superClass != null) {
- ClassNode corrected = getCorrectedClassNode(type, superClass, false);
- extractSuperClassGenerics(corrected, target, spec);
+ extractSuperClassGenerics(correctToGenericsSpecRecurse(createGenericsSpec(type), superClass), target, spec);
} else {
// if we reach here, we have an unhandled case
throw new GroovyBugError("The type " + type + " seems not to normally extend " + target + ". Sorry, I cannot handle this.");
@@ -907,39 +904,60 @@ public class GenericsUtils {
}
/**
- * Check whether the ClassNode has non generics placeholders, aka not placeholder
+ * Checks if the type has any non-placeholder (aka resolved) generics.
*
- * @param parameterizedType the class node
- * @return the result
* @since 3.0.0
*/
- public static boolean hasNonPlaceHolders(ClassNode parameterizedType) {
- return checkPlaceHolders(parameterizedType, genericsType -> !genericsType.isPlaceholder());
+ public static boolean hasNonPlaceHolders(final ClassNode type) {
+ return checkPlaceHolders(type, gt -> !gt.isPlaceholder());
}
/**
- * Check whether the ClassNode has generics placeholders
- * @param parameterizedType the class node
- * @return the result
+ * Checks if the type has any placeholder (aka unresolved) generics.
+ *
* @since 3.0.0
*/
- public static boolean hasPlaceHolders(ClassNode parameterizedType) {
- return checkPlaceHolders(parameterizedType, GenericsType::isPlaceholder);
+ public static boolean hasPlaceHolders(final ClassNode type) {
+ return checkPlaceHolders(type, gt -> gt.isPlaceholder());
}
- private static boolean checkPlaceHolders(ClassNode parameterizedType, Predicate<GenericsType> p) {
- if (null == parameterizedType) return false;
-
- GenericsType[] genericsTypes = parameterizedType.getGenericsTypes();
-
- if (null == genericsTypes) return false;
-
- for (GenericsType genericsType : genericsTypes) {
- if (p.test(genericsType)) {
- return true;
+ private static boolean checkPlaceHolders(final ClassNode type, final Predicate<GenericsType> p) {
+ if (type != null) {
+ GenericsType[] genericsTypes = type.getGenericsTypes();
+ if (genericsTypes != null) {
+ for (GenericsType genericsType : genericsTypes) {
+ if (p.test(genericsType)) {
+ return true;
+ }
+ }
}
}
+ return false;
+ }
+ /**
+ * Checks for any placeholder (aka unresolved) generics.
+ */
+ public static boolean hasUnresolvedGenerics(final ClassNode type) {
+ if (type.isGenericsPlaceHolder()) return true;
+ if (type.isArray()) {
+ return hasUnresolvedGenerics(type.getComponentType());
+ }
+ GenericsType[] genericsTypes = type.getGenericsTypes();
+ if (genericsTypes != null) {
+ for (GenericsType genericsType : genericsTypes) {
+ if (genericsType.isPlaceholder()) return true;
+ ClassNode lowerBound = genericsType.getLowerBound();
+ ClassNode[] upperBounds = genericsType.getUpperBounds();
+ if (lowerBound != null) {
+ if (hasUnresolvedGenerics(lowerBound)) return true;
+ } else if (upperBounds != null) {
+ for (ClassNode upperBound : upperBounds) {
+ if (hasUnresolvedGenerics(upperBound)) return true;
+ }
+ }
+ }
+ }
return false;
}
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 b569fc9..ec5c502 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
@@ -105,7 +105,6 @@ import static org.codehaus.groovy.ast.ClassHelper.make;
import static org.codehaus.groovy.ast.ClassHelper.makeWithoutCaching;
import static org.codehaus.groovy.ast.ClassHelper.short_TYPE;
import static org.codehaus.groovy.ast.ClassHelper.void_WRAPPER_TYPE;
-import static org.codehaus.groovy.ast.tools.GenericsUtils.getSuperClass;
import static org.codehaus.groovy.runtime.DefaultGroovyMethods.asBoolean;
import static org.codehaus.groovy.syntax.Types.BITWISE_AND;
import static org.codehaus.groovy.syntax.Types.BITWISE_AND_EQUAL;
@@ -1730,7 +1729,7 @@ public abstract class StaticTypeCheckingSupport {
* Should the target not have any generics this method does nothing.
*/
static void extractGenericsConnections(final Map<GenericsTypeName, GenericsType> connections, final ClassNode type, final ClassNode target) {
- if (target == null || type == target || !isUsingGenericsOrIsArrayUsingGenerics(target)) return;
+ if (target == null || target == type || !isUsingGenericsOrIsArrayUsingGenerics(target)) return;
if (type == null || type == UNKNOWN_PARAMETER_TYPE) return;
if (target.isGenericsPlaceHolder()) {
@@ -1743,10 +1742,16 @@ public abstract class StaticTypeCheckingSupport {
extractGenericsConnections(connections, type.getGenericsTypes(), target.getGenericsTypes());
} else {
- // first find matching super class or interface
- ClassNode superClass = getSuperClass(type, target);
+ // find matching super class or interface
+ ClassNode superClass = GenericsUtils.getSuperClass(type, target);
if (superClass != null) {
- extractGenericsConnections(connections, getCorrectedClassNode(type, superClass, true), target);
+ if (GenericsUtils.hasUnresolvedGenerics(superClass)) {
+ Map<String, ClassNode> spec = GenericsUtils.createGenericsSpec(type);
+ if (!spec.isEmpty()) {
+ superClass = GenericsUtils.correctToGenericsSpecRecurse(spec, superClass);
+ }
+ }
+ extractGenericsConnections(connections, superClass, target);
} else {
// if we reach here, we have an unhandled case
throw new GroovyBugError("The type " + type + " seems not to normally extend " + target + ". Sorry, I cannot handle this.");
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 6109f8f..3f93d0e 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -1764,11 +1764,9 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
return member;
}
- private void storeWithResolve(final ClassNode typeToResolve, final ClassNode receiver, final ClassNode declaringClass, final boolean isStatic, final Expression expressionToStoreOn) {
- ClassNode type = typeToResolve;
- if (missesGenericsTypes(type)) {
- Map<GenericsTypeName, GenericsType> resolvedPlaceholders = resolvePlaceHoldersFromDeclaration(receiver, declaringClass, null, isStatic);
- type = resolveGenericsWithContext(resolvedPlaceholders, type);
+ private void storeWithResolve(ClassNode type, final ClassNode receiver, final ClassNode declaringClass, final boolean isStatic, final Expression expressionToStoreOn) {
+ if (GenericsUtils.hasUnresolvedGenerics(type)) {
+ type = resolveGenericsWithContext(resolvePlaceHoldersFromDeclaration(receiver, declaringClass, null, isStatic), type);
}
if (expressionToStoreOn instanceof PropertyExpression) {
storeInferredTypeForPropertyExpression((PropertyExpression) expressionToStoreOn, type);
@@ -5136,7 +5134,9 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
Map<GenericsTypeName, GenericsType> connections = new HashMap<>();
extractGenericsConnections(connections, argumentType, paramType);
extractGenericsConnectionsForSuperClassAndInterfaces(resolvedPlaceholders, connections);
+
applyGenericsConnections(connections, resolvedPlaceholders);
+ applyGenericsConnections(placeholdersFromContext, resolvedPlaceholders);
}
}
}
diff --git a/src/test/groovy/transform/stc/ClosureParamTypeInferenceSTCTest.groovy b/src/test/groovy/transform/stc/ClosureParamTypeInferenceSTCTest.groovy
index d991a6f..87416a2 100644
--- a/src/test/groovy/transform/stc/ClosureParamTypeInferenceSTCTest.groovy
+++ b/src/test/groovy/transform/stc/ClosureParamTypeInferenceSTCTest.groovy
@@ -1378,8 +1378,6 @@ method()
void testGroovy9570() {
assertScript '''
- interface Item {}
-
class C<I extends Item> {
Queue<I> queue
@@ -1396,6 +1394,37 @@ method()
}
}
+ interface Item {}
+
+ new C()
+ '''
+ }
+
+ void testGroovy9735() {
+ assertScript '''
+ import groovy.transform.stc.*
+
+ class C<I extends Item> {
+ Queue<I> queue
+
+ def c = { ->
+ x(queue) { I item ->
+ println item
+ }
+ }
+
+ def m() {
+ x(queue) { I item ->
+ println item
+ }
+ }
+
+ def <T> T x(Collection<T> y, @ClosureParams(FirstParam.FirstGenericType) Closure z) {
+ }
+ }
+
+ interface Item {}
+
new C()
'''
}