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 2021/11/12 16:48:23 UTC
[groovy] branch master updated: GROOVY-10229, GROOVY-10339,
GROOVY-10347: STC: merging generic results
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 d520131 GROOVY-10229, GROOVY-10339, GROOVY-10347: STC: merging generic results
d520131 is described below
commit d5201313481d9f47d26e5aeb9e3d538be9d6f733
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Fri Nov 12 09:44:17 2021 -0600
GROOVY-10229, GROOVY-10339, GROOVY-10347: STC: merging generic results
---
.../groovy/ast/tools/WideningCategories.java | 24 ++---
.../transform/stc/StaticTypeCheckingSupport.java | 100 +++++++++++++--------
.../transform/stc/StaticTypeCheckingVisitor.java | 8 +-
3 files changed, 76 insertions(+), 56 deletions(-)
diff --git a/src/main/java/org/codehaus/groovy/ast/tools/WideningCategories.java b/src/main/java/org/codehaus/groovy/ast/tools/WideningCategories.java
index dfb4f99..e7de73f 100644
--- a/src/main/java/org/codehaus/groovy/ast/tools/WideningCategories.java
+++ b/src/main/java/org/codehaus/groovy/ast/tools/WideningCategories.java
@@ -95,14 +95,14 @@ public class WideningCategories {
* always sorted. It is not important what sort is used, as long as the result is constant.
*/
private static final Comparator<ClassNode> INTERFACE_CLASSNODE_COMPARATOR = (cn1, cn2) -> {
- int interfaceCountForO1 = cn1.getInterfaces().length;
- int interfaceCountForO2 = cn2.getInterfaces().length;
- if (interfaceCountForO1 > interfaceCountForO2) return -1;
- if (interfaceCountForO1 < interfaceCountForO2) return 1;
- int methodCountForO1 = cn1.getMethods().size();
- int methodCountForO2 = cn2.getMethods().size();
- if (methodCountForO1 > methodCountForO2) return -1;
- if (methodCountForO1 < methodCountForO2) return 1;
+ int interfaceCount1 = cn1.getInterfaces().length;
+ int interfaceCount2 = cn2.getInterfaces().length;
+ if (interfaceCount1 > interfaceCount2) return -1;
+ if (interfaceCount1 < interfaceCount2) return 1;
+ int methodCount1 = cn1.getMethods().size();
+ int methodCount2 = cn2.getMethods().size();
+ if (methodCount1 > methodCount2) return -1;
+ if (methodCount1 < methodCount2) return 1;
return cn1.getName().compareTo(cn2.getName());
};
@@ -190,7 +190,7 @@ public class WideningCategories {
* @return first common supertype
*/
public static ClassNode lowestUpperBound(final List<ClassNode> nodes) {
- if (nodes.size()==1) return nodes.get(0);
+ if (nodes.size() == 1) return nodes.get(0);
return lowestUpperBound(nodes.get(0), lowestUpperBound(nodes.subList(1, nodes.size())));
}
@@ -229,8 +229,8 @@ public class WideningCategories {
ClassNode psc = superClass.isUsingGenerics()?parameterizeLowestUpperBound(superClass, a, b, lub):superClass;
ClassNode[] interfaces = lub.getInterfaces();
- ClassNode[] pinterfaces = new ClassNode[interfaces.length];
- for (int i = 0, interfacesLength = interfaces.length; i < interfacesLength; i++) {
+ ClassNode[] pinterfaces = interfaces.clone();
+ for (int i = 0, n = interfaces.length; i < n; i += 1) {
final ClassNode icn = interfaces[i];
if (icn.isUsingGenerics()) {
pinterfaces[i] = parameterizeLowestUpperBound(icn, a, b, lub);
@@ -259,7 +259,7 @@ public class WideningCategories {
* @return the class node representing the parameterized lowest upper bound
*/
private static ClassNode parameterizeLowestUpperBound(final ClassNode lub, final ClassNode a, final ClassNode b, final ClassNode fallback) {
- if (!lub.isUsingGenerics()) return lub;
+ if (!lub.isUsingGenerics() || a.toString(false).equals(b.toString(false))) return lub;
// a common super type exists, all we have to do is to parameterize
// it according to the types provided by the two class nodes
ClassNode holderForA = findGenericsTypeHolderForClass(a, lub);
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 31c8d79..8ed22d5 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
@@ -1605,9 +1605,7 @@ public abstract class StaticTypeCheckingSupport {
if (newValue == null) {
newValue = connections.get(entry.getKey());
if (newValue != null) { // GROOVY-10315, GROOVY-10317
- ClassNode o = makeClassSafe0(CLASS_Type, oldValue),
- n = makeClassSafe0(CLASS_Type, newValue);
- newValue = lowestUpperBound(o,n).getGenericsTypes()[0];
+ newValue = getCombinedGenericsType(oldValue, newValue);
}
}
if (newValue == null) {
@@ -1722,7 +1720,7 @@ public abstract class StaticTypeCheckingSupport {
if (type == null || type == UNKNOWN_PARAMETER_TYPE) return;
if (target.isGenericsPlaceHolder()) {
- connections.put(new GenericsTypeName(target.getUnresolvedName()), new GenericsType(type));
+ storeGenericsConnection(connections, target.getUnresolvedName(), new GenericsType(type));
} else if (type.isGenericsPlaceHolder()) {
// "T extends java.util.List<X> -> java.util.List<E>" vs "java.util.List<E>"
@@ -1757,11 +1755,6 @@ public abstract class StaticTypeCheckingSupport {
}
}
- public static ClassNode getCorrectedClassNode(final ClassNode type, final ClassNode superClass, final boolean handlingGenerics) {
- if (handlingGenerics && GenericsUtils.hasUnresolvedGenerics(type)) return superClass.getPlainNodeReference();
- return GenericsUtils.correctToGenericsSpecRecurse(GenericsUtils.createGenericsSpec(type), superClass);
- }
-
private static void extractGenericsConnections(final Map<GenericsTypeName, GenericsType> connections, final GenericsType[] usage, final GenericsType[] declaration) {
// if declaration does not provide generics, there is no connection to make
if (usage == null || declaration == null || declaration.length == 0) return;
@@ -1771,7 +1764,7 @@ public abstract class StaticTypeCheckingSupport {
for (int i = 0, n = usage.length; i < n; i += 1) {
GenericsType ui = usage[i], di = declaration[i];
if (di.isPlaceholder()) {
- connections.put(new GenericsTypeName(di.getName()), ui);
+ storeGenericsConnection(connections, di.getName(), ui);
} else if (di.isWildcard()) {
ClassNode lowerBound = di.getLowerBound(), upperBounds[] = di.getUpperBounds();
if (ui.isWildcard()) {
@@ -1782,7 +1775,7 @@ public abstract class StaticTypeCheckingSupport {
if (boundType.isGenericsPlaceHolder()) { // GROOVY-9998
String placeholderName = boundType.getUnresolvedName();
ui = new GenericsType(ui.getType()); ui.setWildcard(true);
- connections.put(new GenericsTypeName(placeholderName), ui);
+ storeGenericsConnection(connections, placeholderName, ui);
} else { // di like "? super Collection<T>" and ui like "List<Type>"
extractGenericsConnections(connections, ui.getType(), boundType);
}
@@ -1800,13 +1793,18 @@ public abstract class StaticTypeCheckingSupport {
ClassNode ui = usage[i];
ClassNode di = declaration[i];
if (di.isGenericsPlaceHolder()) {
- connections.put(new GenericsTypeName(di.getUnresolvedName()), new GenericsType(ui));
+ storeGenericsConnection(connections, di.getUnresolvedName(), new GenericsType(ui));
} else if (di.isUsingGenerics()) {
extractGenericsConnections(connections, ui.getGenericsTypes(), di.getGenericsTypes());
}
}
}
+ private static void storeGenericsConnection(final Map<GenericsTypeName, GenericsType> connections, final String placeholderName, final GenericsType gt) {
+ //connections.merge(new GenericsTypeName(placeholderName), gt, (gt1, gt2) -> getCombinedGenericsType(gt1, gt2));
+ connections.put(new GenericsTypeName(placeholderName), gt);
+ }
+
static GenericsType[] getGenericsWithoutArray(final ClassNode type) {
if (type.isArray()) return getGenericsWithoutArray(type.getComponentType());
return type.getGenericsTypes();
@@ -1923,16 +1921,11 @@ public abstract class StaticTypeCheckingSupport {
return genericsType.getType();
}
- private static Map<GenericsTypeName, GenericsType> getGenericsParameterMapOfThis(final ClassNode cn) {
- if (cn == null) return null;
- Map<GenericsTypeName, GenericsType> map = null;
- if (cn.getEnclosingMethod() != null) {
- map = extractGenericsParameterMapOfThis(cn.getEnclosingMethod());
- } else if (cn.getOuterClass() != null) {
- map = getGenericsParameterMapOfThis(cn.getOuterClass());
- }
- map = mergeGenerics(map, cn.getGenericsTypes());
- return map;
+ static GenericsType getCombinedGenericsType(final GenericsType gt1, final GenericsType gt2) {
+ ClassNode cn1 = makeClassSafe0(CLASS_Type, gt1);
+ ClassNode cn2 = makeClassSafe0(CLASS_Type, gt2);
+ ClassNode lub = lowestUpperBound(cn1,cn2);
+ return lub.getGenericsTypes()[0];
}
/**
@@ -1982,37 +1975,60 @@ public abstract class StaticTypeCheckingSupport {
}
static Map<GenericsTypeName, GenericsType> extractGenericsParameterMapOfThis(final TypeCheckingContext context) {
- ClassNode cn = context.getEnclosingClassNode();
+ ClassNode cn = context.getEnclosingClassNode();
MethodNode mn = context.getEnclosingMethod();
// GROOVY-9570: find the innermost class or method
if (cn != null && cn.getEnclosingMethod() == mn) {
- return getGenericsParameterMapOfThis(cn);
+ return extractGenericsParameterMapOfThis(cn);
+ } else {
+ return extractGenericsParameterMapOfThis(mn);
}
- return extractGenericsParameterMapOfThis(mn);
}
private static Map<GenericsTypeName, GenericsType> extractGenericsParameterMapOfThis(final MethodNode mn) {
if (mn == null) return null;
- Map<GenericsTypeName, GenericsType> map;
- if (mn.isStatic()) {
- map = new HashMap<>();
- } else {
- map = getGenericsParameterMapOfThis(mn.getDeclaringClass());
+ Map<GenericsTypeName, GenericsType> map = null;
+ if (!mn.isStatic()) {
+ map = extractGenericsParameterMapOfThis(mn.getDeclaringClass());
}
- return mergeGenerics(map, mn.getGenericsTypes());
+ GenericsType[] gts = mn.getGenericsTypes();
+ if (gts != null) {
+ if (map == null) map = new HashMap<>();
+ for (GenericsType gt : gts) {
+ assert gt.isPlaceholder();
+ map.put(new GenericsTypeName(gt.getName()), gt);
+ }
+ }
+
+ return map;
}
- private static Map<GenericsTypeName, GenericsType> mergeGenerics(Map<GenericsTypeName, GenericsType> current, final GenericsType[] newGenerics) {
- if (newGenerics == null || newGenerics.length == 0) return current;
- if (current == null) current = new HashMap<>();
- for (GenericsType gt : newGenerics) {
- if (!gt.isPlaceholder()) continue;
- GenericsTypeName name = new GenericsTypeName(gt.getName());
- if (!current.containsKey(name)) current.put(name, gt);
+ private static Map<GenericsTypeName, GenericsType> extractGenericsParameterMapOfThis(final ClassNode cn) {
+ if (cn == null) return null;
+
+ Map<GenericsTypeName, GenericsType> map = null;
+ if ((cn.getModifiers() & Opcodes.ACC_STATIC) == 0) {
+ if (cn.getEnclosingMethod() != null) {
+ map = extractGenericsParameterMapOfThis(cn.getEnclosingMethod());
+ } else if (cn.getOuterClass() != null) {
+ map = extractGenericsParameterMapOfThis(cn.getOuterClass());
+ }
+ }
+
+ if (!(cn instanceof InnerClassNode && ((InnerClassNode) cn).isAnonymous())) {
+ GenericsType[] gts = cn.getGenericsTypes();
+ if (gts != null) {
+ if (map == null) map = new HashMap<>();
+ for (GenericsType gt : gts) {
+ assert gt.isPlaceholder();
+ map.put(new GenericsTypeName(gt.getName()), gt);
+ }
+ }
}
- return current;
+
+ return map;
}
/**
@@ -2181,6 +2197,12 @@ public abstract class StaticTypeCheckingSupport {
return GeneralUtils.getInterfacesAndSuperInterfaces(node);
}
+ @Deprecated
+ public static ClassNode getCorrectedClassNode(final ClassNode cn, final ClassNode sc, final boolean completed) {
+ if (completed && GenericsUtils.hasUnresolvedGenerics(cn)) return sc.getPlainNodeReference();
+ return GenericsUtils.correctToGenericsSpecRecurse(GenericsUtils.createGenericsSpec(cn), sc);
+ }
+
/**
* Returns true if the class node represents a the class node for the Class class
* and if the parametrized type is a neither a placeholder or a wildcard. For example,
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 59aa5fb..f4a51b2 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -211,7 +211,6 @@ import static org.codehaus.groovy.ast.tools.ClosureUtils.getResolveStrategyName;
import static org.codehaus.groovy.ast.tools.ClosureUtils.hasImplicitParameter;
import static org.codehaus.groovy.ast.tools.GeneralUtils.args;
import static org.codehaus.groovy.ast.tools.GeneralUtils.binX;
-import static org.codehaus.groovy.ast.tools.GeneralUtils.block;
import static org.codehaus.groovy.ast.tools.GeneralUtils.callX;
import static org.codehaus.groovy.ast.tools.GeneralUtils.castX;
import static org.codehaus.groovy.ast.tools.GeneralUtils.constX;
@@ -278,6 +277,7 @@ import static org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.findTa
import static org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.fullyResolve;
import static org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.fullyResolveType;
import static org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.getCombinedBoundType;
+import static org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.getCombinedGenericsType;
import static org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.getGenericsWithoutArray;
import static org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.getOperationName;
import static org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.implementsInterfaceOrIsSubclassOf;
@@ -5341,10 +5341,8 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
Map<GenericsTypeName, GenericsType> connections = new HashMap<>();
extractGenericsConnections(connections, wrapTypeIfNecessary(argumentType), paramType);
connections.forEach((gtn, gt) -> resolvedPlaceholders.merge(gtn, gt, (gt1, gt2) -> {
- // GROOVY-10339: incorporate additional witness
- ClassNode cn1 = makeClassSafe0(CLASS_Type, gt1);
- ClassNode cn2 = makeClassSafe0(CLASS_Type, gt2);
- return lowestUpperBound(cn1,cn2).getGenericsTypes()[0];
+ // GROOVY-10339: incorporate another witness
+ return getCombinedGenericsType(gt1, gt2);
}));
}
}