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);
                         }));
                     }
                 }