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/04/08 17:36:02 UTC

[groovy] branch GROOVY_4_0_X updated: GROOVY-10576: "?" source and target "? extends Object"

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

emilles pushed a commit to branch GROOVY_4_0_X
in repository https://gitbox.apache.org/repos/asf/groovy.git


The following commit(s) were added to refs/heads/GROOVY_4_0_X by this push:
     new 5542303583 GROOVY-10576: "?" source and target "? extends Object"
5542303583 is described below

commit 55423035831a70ec735ba0b4432cd8f56a366b38
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Fri Apr 8 11:59:21 2022 -0500

    GROOVY-10576: "?" source and target "? extends Object"
---
 .../java/org/codehaus/groovy/ast/GenericsType.java |   4 +-
 .../groovy/transform/stc/GenericsSTCTest.groovy    | 105 ++++++++++++---------
 2 files changed, 63 insertions(+), 46 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/ast/GenericsType.java b/src/main/java/org/codehaus/groovy/ast/GenericsType.java
index ab7dfbddb3..cd5414ad11 100644
--- a/src/main/java/org/codehaus/groovy/ast/GenericsType.java
+++ b/src/main/java/org/codehaus/groovy/ast/GenericsType.java
@@ -412,8 +412,8 @@ public class GenericsType extends ASTNode {
                                                 match = gt.checkGenerics(classNodeType.getLowerBound());
                                             } else if (classNodeType.getUpperBounds() != null) {
                                                 match = gt.checkGenerics(classNodeType.getUpperBounds()[0]);
-                                            } else {
-                                                match = false; // "?" (from Comparable<?>) does not satisfy anything
+                                            } else { // GROOVY-10576: "?" vs "? extends Object" (citation required) or no match
+                                                match = (!gt.isPlaceholder() && !gt.isWildcard() && isObjectType(gt.getType()));
                                             }
                                         } else {
                                             match = implementsInterfaceOrIsSubclassOf(classNodeType.getType(), gt.getType());
diff --git a/src/test/groovy/transform/stc/GenericsSTCTest.groovy b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
index efa15d8f22..0551a70825 100644
--- a/src/test/groovy/transform/stc/GenericsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
@@ -1570,44 +1570,6 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
         'Cannot call A#<init>(java.lang.Class<java.lang.String>, java.lang.Class<java.lang.Integer>) with arguments [java.lang.Class<java.lang.Integer>, java.lang.Class<java.lang.String>]'
     }
 
-    void testMethodCallWithMapParameterUnbounded() {
-        assertScript """
-            import static ${this.class.name}.isEmpty
-            class C {
-                Map<String, ?> map = new HashMap()
-            }
-            assert isEmpty(new C().map)
-        """
-    }
-
-    // GROOVY-9460
-    void testMethodCallWithClassParameterUnbounded() {
-        assertScript '''
-            class Bar {
-                static void baz(Class<?> target) {
-                }
-            }
-            class Foo<X> { // cannot be "T" because that matches type parameter in Class
-                void test(Class<X> c) {
-                    Bar.baz(c) // Cannot call Bar#baz(Class<?>) with arguments [Class<X>]
-                }
-            }
-            new Foo<String>().test(String.class)
-        '''
-    }
-
-    // GROOVY-10525
-    void testMethodCallWithClassParameterUnbounded2() {
-        assertScript '''
-            @Grab('javax.validation:validation-api:1.1.0.Final')
-            import javax.validation.Validator
-
-            void test(Object bean, List<Class<?>> types, Validator validator) {
-                validator.validate(bean, types as Class<?>[])
-            }
-        '''
-    }
-
     void testConstructorCallWithClassParameterUsingClassLiteralArg() {
         assertScript '''
             class A {}
@@ -1634,21 +1596,21 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
-    void testPutMethodWithPrimitiveValue() {
+    void testPutWithPrimitiveValue() {
         assertScript '''
             def map = new HashMap<String, Integer>()
             map.put('hello', 1)
         '''
     }
 
-    void testPutAtMethodWithPrimitiveValue() {
+    void testPutAtWithPrimitiveValue() {
         assertScript '''
             def map = new HashMap<String, Integer>()
             map['hello'] = 1
         '''
     }
 
-    void testPutMethodWithWrongValueType() {
+    void testPutWithWrongValueType() {
         shouldFailWithMessages '''
             def map = new HashMap<String, Integer>()
             map.put('hello', new Object())
@@ -1656,7 +1618,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
         'Cannot find matching method java.util.HashMap#put(java.lang.String, java.lang.Object). Please check if the declared type is correct and if the method exists.'
     }
 
-    void testPutAtMethodWithWrongValueType() {
+    void testPutAtWithWrongValueType() {
         shouldFailWithMessages '''
             def map = new HashMap<String, Integer>()
             map['hello'] = new Object()
@@ -1665,7 +1627,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-9069
-    void testPutAtMethodWithWrongValueType2() {
+    void testPutAtWithWrongValueType2() {
         shouldFailWithMessages '''
             class ConfigAttribute {
             }
@@ -1681,7 +1643,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
         'Cannot call <K,V> org.codehaus.groovy.runtime.DefaultGroovyMethods#putAt(java.util.Map<K, V>, K, V) with arguments [java.util.Map<java.lang.String, java.util.Map<java.lang.String, java.util.List<java.lang.String>>>, java.lang.String, java.util.LinkedHashMap<java.lang.String, java.util.List<ConfigAttribute>>]'
     }
 
-    void testPutAtMethodWithWrongValueType3() {
+    void testPutAtWithWrongValueType3() {
         assertScript '''
             void test(Map<String, Map<String, List<String>>> maps) {
                 maps.each { String key, Map<String, List<String>> map ->
@@ -1694,6 +1656,61 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
+    // GROOVY-10576
+    void testPutAllWithMapParameterUnbounded() {
+        assertScript '''
+            class C {
+                Map<String,Object> map
+                void test(Map<String,?> m) {
+                    map.putAll(m) // Cannot call Map#putAll(Map<? extends String, ? extends Object>) with arguments [Map<String, ?>]
+                }
+            }
+            def obj = new C(map:[:])
+            obj.test(foo:'bar')
+            def map = obj.map
+
+            assert map == [foo:'bar']
+        '''
+    }
+
+    void testMethodCallWithMapParameterUnbounded() {
+        assertScript """
+            import static ${this.class.name}.isEmpty
+            class C {
+                Map<String,?> map = new HashMap()
+            }
+            assert isEmpty(new C().map)
+        """
+    }
+
+    // GROOVY-9460
+    void testMethodCallWithClassParameterUnbounded() {
+        assertScript '''
+            class Bar {
+                static void baz(Class<?> target) {
+                }
+            }
+            class Foo<X> { // cannot be "T" because that matches type parameter in Class
+                void test(Class<X> c) {
+                    Bar.baz(c) // Cannot call Bar#baz(Class<?>) with arguments [Class<X>]
+                }
+            }
+            new Foo<String>().test(String.class)
+        '''
+    }
+
+    // GROOVY-10525
+    void testMethodCallWithClassParameterUnbounded2() {
+        assertScript '''
+            @Grab('javax.validation:validation-api:1.1.0.Final')
+            import javax.validation.Validator
+
+            void test(Object bean, List<Class<?>> types, Validator validator) {
+                validator.validate(bean, types as Class<?>[])
+            }
+        '''
+    }
+
     void testShouldComplainAboutToInteger() {
         shouldFailWithMessages '''
             class Test {