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 5946717 GROOVY-10055: STC: handle raw type incl. self-referential
type parameter
5946717 is described below
commit 5946717d13b6f8df8b6dfbc3edff902126304587
Author: Eric Milles <[email protected]>
AuthorDate: Mon Oct 18 12:36:47 2021 -0500
GROOVY-10055: STC: handle raw type incl. self-referential type parameter
---
src/main/groovy/groovy/grape/GrapeIvy.groovy | 2 +-
.../transform/stc/StaticTypeCheckingVisitor.java | 51 +++++++++++-----------
.../groovy/transform/stc/GenericsSTCTest.groovy | 29 ++++++++++++
.../classgen/asm/sc/BugsStaticCompileTest.groovy | 2 +-
4 files changed, 57 insertions(+), 27 deletions(-)
diff --git a/src/main/groovy/groovy/grape/GrapeIvy.groovy
b/src/main/groovy/groovy/grape/GrapeIvy.groovy
index 4bb7950..4afe525 100644
--- a/src/main/groovy/groovy/grape/GrapeIvy.groovy
+++ b/src/main/groovy/groovy/grape/GrapeIvy.groovy
@@ -594,7 +594,7 @@ class GrapeIvy implements GrapeEngine {
URI[] resolve(ClassLoader loader, Map args, List depsInfo, Map...
dependencies) {
// check for mutually exclusive arguments
- Set<String> keys = args.keySet()
+ Set<String> keys = (Set<String>) args.keySet()
keys.each { key ->
Set<String> badArgs = MUTUALLY_EXCLUSIVE_KEYS[key]
if (badArgs && !badArgs.disjoint(keys)) {
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 3d051da..2fc0998 100644
---
a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++
b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -5663,7 +5663,7 @@ public class StaticTypeCheckingVisitor extends
ClassCodeVisitorSupport {
}
private static Map<GenericsTypeName, GenericsType>
extractPlaceHolders(final MethodNode method, ClassNode receiver, final
ClassNode declaringClass) {
- Map<GenericsTypeName, GenericsType> resolvedPlaceholders = null;
+ Map<GenericsTypeName, GenericsType> resolvedPlaceHolders = null,
currentPlaceHolders = new HashMap<>();
if (isPrimitiveType(receiver) && !isPrimitiveType(declaringClass)) {
receiver = getWrapper(receiver);
}
@@ -5676,54 +5676,55 @@ public class StaticTypeCheckingVisitor extends
ClassCodeVisitorSupport {
for (ClassNode type : todo) {
ClassNode current = type;
while (current != null) {
- boolean continueLoop = true;
- // extract the place holders
- Map<GenericsTypeName, GenericsType> currentPlaceHolders = new
HashMap<>();
- if (isGenericsPlaceHolderOrArrayOf(declaringClass) ||
declaringClass.equals(current)) {
+ currentPlaceHolders.clear();
+ // GROOVY-10055: handle diamond or raw
+ if (current.getGenericsTypes() != null
+ ? current.getGenericsTypes().length == 0
+ : current.redirect().getGenericsTypes() != null) {
+ for (GenericsType gt :
current.redirect().getGenericsTypes()) {
+ ClassNode cn = gt.getUpperBounds() != null ?
gt.getUpperBounds()[0] : gt.getType().redirect();
+ currentPlaceHolders.put(new
GenericsTypeName(gt.getName()), cn.getPlainNodeReference().asGenericsType());
+ }
+ }
+
+ boolean currentIsDeclaring = current.equals(declaringClass) ||
isGenericsPlaceHolderOrArrayOf(declaringClass);
+ if (currentIsDeclaring) {
extractGenericsConnections(currentPlaceHolders, current,
declaringClass);
- if (method != null) addMethodLevelDeclaredGenerics(method,
currentPlaceHolders);
- continueLoop = false;
+ if (method != null)
+ addMethodLevelDeclaredGenerics(method,
currentPlaceHolders);
} else {
GenericsUtils.extractPlaceholders(current,
currentPlaceHolders);
}
- if (resolvedPlaceholders != null) {
- // merge maps
+ if (resolvedPlaceHolders != null) { // merge maps
for (Map.Entry<GenericsTypeName, GenericsType> entry :
currentPlaceHolders.entrySet()) {
GenericsType gt = entry.getValue();
if (!gt.isPlaceholder()) continue;
- GenericsType referenced = resolvedPlaceholders.get(new
GenericsTypeName(gt.getName()));
+ GenericsType referenced = resolvedPlaceHolders.get(new
GenericsTypeName(gt.getName()));
if (referenced == null) continue;
entry.setValue(referenced);
}
}
- resolvedPlaceholders = currentPlaceHolders;
+ resolvedPlaceHolders = currentPlaceHolders;
// we are done if we are now in the declaring class
- if (!continueLoop) break;
+ if (currentIsDeclaring) break;
- boolean isRawType = (current.getGenericsTypes() == null
- && current.redirect().getGenericsTypes() != null);
current = getNextSuperClass(current, declaringClass);
if (current == null && isClassType(declaringClass)) {
// this can happen if the receiver is Class<Foo>, then
// the actual receiver is Foo and declaringClass is Class
current = declaringClass;
- } else if (isRawType) {
- current = current.getPlainNodeReference();
+ } else {
+ current = applyGenericsContext(currentPlaceHolders,
current);
}
}
}
- if (resolvedPlaceholders == null) {
- String descriptor = "<>";
- if (method != null) descriptor = method.getTypeDescriptor();
- throw new GroovyBugError(
- "Declaring class for method call to '" +
- descriptor + "' declared in " +
declaringClass.getName() +
- " was not matched with found receiver " +
receiver.getName() + "." +
- " This should not have happened!");
+ if (resolvedPlaceHolders == null) {
+ throw new GroovyBugError("Declaring class for method call to '" +
(method != null ? method.getTypeDescriptor() : "<>") +
+ "' declared in " + declaringClass.getName() + " was not
matched with found receiver " + receiver.getName() + ". This should not have
happened!");
}
- return resolvedPlaceholders;
+ return resolvedPlaceHolders;
}
protected boolean typeCheckMethodsWithGenericsOrFail(final ClassNode
receiver, final ClassNode[] arguments, final MethodNode candidateMethod, final
Expression location) {
diff --git a/src/test/groovy/transform/stc/GenericsSTCTest.groovy
b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
index c49b4a6..259a8a9 100644
--- a/src/test/groovy/transform/stc/GenericsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
@@ -3898,6 +3898,35 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase
{
}
}
+ // GROOVY-10055
+ void testSelfReferentialTypeParameter2() {
+ assertScript '''
+ abstract class A<Self extends A<Self>> {
+ Self foo(inputs) {
+ // ...
+ this
+ }
+ }
+ abstract class B<Self extends B<Self>> extends A<Self> {
+ Self bar(inputs) {
+ // ...
+ this
+ }
+ }
+ class C<Self extends C<Self>> extends B<Self> { // see
org.testcontainers.containers.PostgreSQLContainer
+ Self baz(inputs) {
+ // ...
+ this
+ }
+ }
+
+ new C<>()
+ .foo('x')
+ .bar('y') // error
+ .baz('z') // error
+ '''
+ }
+
// GROOVY-7804
void testParameterlessClosureToGenericSAMTypeArgumentCoercion() {
assertScript '''
diff --git
a/src/test/org/codehaus/groovy/classgen/asm/sc/BugsStaticCompileTest.groovy
b/src/test/org/codehaus/groovy/classgen/asm/sc/BugsStaticCompileTest.groovy
index 0377642..5576b16 100644
--- a/src/test/org/codehaus/groovy/classgen/asm/sc/BugsStaticCompileTest.groovy
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/BugsStaticCompileTest.groovy
@@ -1170,7 +1170,7 @@ assert it.next() == 1G
@ASTTest(phase=INSTRUCTION_SELECTION, value={
def ift = node.getNodeMetaData(INFERRED_TYPE)
assert ift == SET_TYPE
- assert ift.genericsTypes == null
+ assert ift.genericsTypes[0].type == OBJECT_TYPE
})
def set = map.keySet()
def key = set[0]