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/08/16 15:46:37 UTC

[groovy] branch master updated: GROOVY-8828: STC: `UnionTypeClassNode` plain node reference semantics

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 0d07740929 GROOVY-8828: STC: `UnionTypeClassNode` plain node reference semantics
0d07740929 is described below

commit 0d0774092977e93351182e32a1fd9349f0a2a23c
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Tue Aug 16 10:17:13 2022 -0500

    GROOVY-8828: STC: `UnionTypeClassNode` plain node reference semantics
---
 .../transform/stc/StaticTypeCheckingSupport.java   | 27 +++++++++-------------
 .../groovy/transform/stc/UnionTypeClassNode.java   | 23 ++++++++++++------
 .../transform/stc/TypeInferenceSTCTest.groovy      | 16 +++++++++++++
 3 files changed, 43 insertions(+), 23 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 1fcab91150..4d4090fc82 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
@@ -889,31 +889,26 @@ public abstract class StaticTypeCheckingSupport {
     }
 
     public static boolean implementsInterfaceOrIsSubclassOf(final ClassNode type, final ClassNode superOrInterface) {
-        boolean result = (type.equals(superOrInterface)
+        if (type.isArray() && superOrInterface.isArray()) {
+            return implementsInterfaceOrIsSubclassOf(type.getComponentType(), superOrInterface.getComponentType());
+        }
+        if (type == UNKNOWN_PARAMETER_TYPE // aka null
                 || type.isDerivedFrom(superOrInterface)
-                || type.implementsInterface(superOrInterface)
-                || type == UNKNOWN_PARAMETER_TYPE);
-        if (result) {
+                || type.implementsInterface(superOrInterface)) {
             return true;
         }
         if (superOrInterface instanceof WideningCategories.LowestUpperBoundClassNode) {
-            WideningCategories.LowestUpperBoundClassNode cn = (WideningCategories.LowestUpperBoundClassNode) superOrInterface;
-            result = implementsInterfaceOrIsSubclassOf(type, cn.getSuperClass());
-            if (result) {
-                for (ClassNode interfaceNode : cn.getInterfaces()) {
-                    result = type.implementsInterface(interfaceNode);
-                    if (!result) break;
-                }
+            if (implementsInterfaceOrIsSubclassOf(type, superOrInterface.getSuperClass())
+                    && Arrays.stream(superOrInterface.getInterfaces()).allMatch(type::implementsInterface)) {
+                return true;
             }
-            if (result) return true;
         } else if (superOrInterface instanceof UnionTypeClassNode) {
             for (ClassNode delegate : ((UnionTypeClassNode) superOrInterface).getDelegates()) {
-                if (implementsInterfaceOrIsSubclassOf(type, delegate)) return true;
+                if (implementsInterfaceOrIsSubclassOf(type, delegate)) {
+                    return true;
+                }
             }
         }
-        if (type.isArray() && superOrInterface.isArray()) {
-            return implementsInterfaceOrIsSubclassOf(type.getComponentType(), superOrInterface.getComponentType());
-        }
         if (isGroovyObjectType(superOrInterface) && isBeingCompiled(type) && !type.isInterface()) {//TODO: !POJO !Trait
             return true;
         }
diff --git a/src/main/java/org/codehaus/groovy/transform/stc/UnionTypeClassNode.java b/src/main/java/org/codehaus/groovy/transform/stc/UnionTypeClassNode.java
index 1513421c27..7d79463d8d 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/UnionTypeClassNode.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/UnionTypeClassNode.java
@@ -43,6 +43,7 @@ import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.StringJoiner;
 
 /**
  * This class node type is very special and should only be used by the static type checker
@@ -57,18 +58,17 @@ import java.util.Set;
 class UnionTypeClassNode extends ClassNode {
     private final ClassNode[] delegates;
 
-    public UnionTypeClassNode(ClassNode... classNodes) {
-        super("<UnionType:" + asArrayDescriptor(classNodes) + ">", 0, ClassHelper.OBJECT_TYPE);
+    UnionTypeClassNode(final ClassNode... classNodes) {
+        super(makeName(classNodes), 0, ClassHelper.OBJECT_TYPE);
         delegates = classNodes == null ? ClassNode.EMPTY_ARRAY : classNodes;
     }
 
-    private static String asArrayDescriptor(ClassNode... nodes) {
-        StringBuilder sb = new StringBuilder();
+    private static String makeName(final ClassNode[] nodes) {
+        StringJoiner sj = new StringJoiner("+", "<UnionType:", ">");
         for (ClassNode node : nodes) {
-            if (sb.length() > 0) sb.append("+");
-            sb.append(node.getText());
+            sj.add(node.getText());
         }
-        return sb.toString();
+        return sj.toString();
     }
 
     public ClassNode[] getDelegates() {
@@ -306,6 +306,15 @@ class UnionTypeClassNode extends ClassNode {
         return nodes;
     }
 
+    @Override
+    public ClassNode getPlainNodeReference(final boolean skipPrimitives) {
+        int n = delegates.length; ClassNode[] plainNodes = new ClassNode[n];
+        for (int i = 0; i < n; i += 1) {
+            plainNodes[i] = delegates[i].getPlainNodeReference(skipPrimitives);
+        }
+        return new UnionTypeClassNode(plainNodes);
+    }
+
     @Override
     public List<PropertyNode> getProperties() {
         List<PropertyNode> nodes = new LinkedList<PropertyNode>();
diff --git a/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy b/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy
index c172240660..372cc054c8 100644
--- a/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy
+++ b/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy
@@ -396,6 +396,22 @@ class TypeInferenceSTCTest extends StaticTypeCheckingTestCase {
         }
     }
 
+    // GROOVY-8828
+    void testMultipleInstanceOf7() {
+        assertScript '''
+            interface Foo { }
+            interface Bar { String name() }
+
+            Map<String, Foo> map = [:]
+            map.values().each { foo ->
+                if (foo instanceof Bar) {
+                    String name = foo.name() // method available through Bar
+                    map.put(name, foo)       // second parameter expects Foo
+                }
+            }
+        '''
+    }
+
     // GROOVY-8523
     void testNotInstanceof1() {
         assertScript '''