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/09/12 22:06:58 UTC

[groovy] branch GROOVY_3_0_X updated: GROOVY-5692, GROOVY-10006, GROOVY-10339: STC: multiple witnesses in call

This is an automated email from the ASF dual-hosted git repository.

emilles 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 b830dd382d GROOVY-5692, GROOVY-10006, GROOVY-10339: STC: multiple witnesses in call
b830dd382d is described below

commit b830dd382d1ad834dd9745761a05af100bd674d9
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Mon Sep 12 16:51:44 2022 -0500

    GROOVY-5692, GROOVY-10006, GROOVY-10339: STC: multiple witnesses in call
---
 .../groovy/ast/tools/WideningCategories.java       | 14 +++++++++++++
 .../transform/stc/StaticTypeCheckingSupport.java   | 24 +++++++++++++---------
 .../groovy/transform/stc/GenericsSTCTest.groovy    |  6 +++---
 3 files changed, 31 insertions(+), 13 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 4c4ba12648..77fe8dc147 100644
--- a/src/main/java/org/codehaus/groovy/ast/tools/WideningCategories.java
+++ b/src/main/java/org/codehaus/groovy/ast/tools/WideningCategories.java
@@ -649,6 +649,20 @@ public class WideningCategories {
             return text;
         }
 
+        @Override
+        public GenericsType asGenericsType() {
+            ClassNode[] ubs;
+            if (upper.equals(OBJECT_TYPE)) {
+                ubs = interfaces; // Object is implicit
+            } else {
+                ubs = new ClassNode[interfaces.length + 1]; ubs[0] = upper;
+                System.arraycopy(interfaces, 0, ubs, 1, interfaces.length);
+            }
+            GenericsType gt = new GenericsType(ClassHelper.makeWithoutCaching("?"), ubs, null);
+            gt.setWildcard(true);
+            return gt;
+        }
+
         @Override
         public ClassNode getPlainNodeReference() {
             ClassNode[] intf = interfaces==null?null:new ClassNode[interfaces.length];
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 6ca1e6bc04..3bcb9c1062 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
@@ -1533,17 +1533,21 @@ public abstract class StaticTypeCheckingSupport {
                 continue;
             }
             if (!compatibleConnection(resolved, connection)) {
-                if (!(resolved.isPlaceholder() || resolved.isWildcard())
-                        && !fixedGenericsPlaceHolders.contains(entry.getKey())
-                        && compatibleConnection(connection, resolved)) {
-                    // we did for example find T=String and now check against
-                    // T=Object, which fails the first compatibleConnection check
-                    // but since T=Object works for both, the second one will pass
-                    // and we need to change the type for T to the more general one
-                    resolvedMethodGenerics.put(entry.getKey(), connection);
-                } else {
-                    return false;
+                if (!resolved.isPlaceholder() && !resolved.isWildcard()
+                        && !fixedGenericsPlaceHolders.contains(entry.getKey())) {
+                    // GROOVY-5692, GROOVY-10006: multiple witnesses
+                    if (compatibleConnection(connection, resolved)) {
+                        // was "T=Integer" and now is "T=Number" or "T=Object"
+                        resolvedMethodGenerics.put(entry.getKey(), connection);
+                        continue;
+                    } else if (!connection.isPlaceholder() && !connection.isWildcard()) {
+                        // combine "T=Integer" and "T=String" to produce "T=? extends Serializable & Comparable<...>"
+                        ClassNode lub = WideningCategories.lowestUpperBound(connection.getType(), resolved.getType());
+                        resolvedMethodGenerics.put(entry.getKey(), lub.asGenericsType());
+                        continue;
+                    }
                 }
+                return false; // incompatible
             }
         }
         return true;
diff --git a/src/test/groovy/transform/stc/GenericsSTCTest.groovy b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
index 2e856badd6..da8b9dba83 100644
--- a/src/test/groovy/transform/stc/GenericsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
@@ -608,7 +608,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
         }
     }
 
-    @NotYetImplemented // GROOVY-10339
+    // GROOVY-10339
     void testReturnTypeInferenceWithMethodGenerics22() {
         for (type in ['Comparable', 'Serializable']) {
             assertScript """
@@ -2952,7 +2952,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
-    @NotYetImplemented // GROOVY-5692, GROOVY-10006
+    // GROOVY-5692, GROOVY-10006
     void testCompatibleArgumentsForPlaceholders1() {
         assertScript '''
             def <T> T test(T one, T two) { }
@@ -2968,7 +2968,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
-    @NotYetImplemented // GROOVY-5692
+    // GROOVY-5692
     void testCompatibleArgumentsForPlaceholders2() {
         assertScript '''
             def <T> boolean test(T one, List<T> many) { }