You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by pa...@apache.org on 2021/03/15 07:18:20 UTC

[groovy] branch GROOVY_3_0_X updated (fcc4875 -> 323df74)

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

paulk pushed a change to branch GROOVY_3_0_X
in repository https://gitbox.apache.org/repos/asf/groovy.git.


    from fcc4875  GROOVY-9882: add test case
     new 39c289a  GROOVY-9902: STC: allow method checking with partial generic information
     new 323df74  GROOVY-9981: helper methods for where pos/neg zero should be treated equal (to help avoid potentially confusing cases and help with writing code that works across 3/4) (closes #1518)

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../java/org/codehaus/groovy/ast/GenericsType.java | 16 ++++-----
 .../groovy/runtime/DefaultGroovyMethods.java       | 26 ++++++++++++++
 .../groovy/runtime/NumberAwareComparator.java      | 20 +++++++++++
 .../transform/stc/StaticTypeCheckingSupport.java   |  5 +--
 src/test/groovy/bugs/Groovy6786Bug.groovy          | 39 +++++++++------------
 .../groovy/transform/stc/GenericsSTCTest.groovy    | 40 ++++++++++++++++++++++
 6 files changed, 111 insertions(+), 35 deletions(-)


[groovy] 01/02: GROOVY-9902: STC: allow method checking with partial generic information

Posted by pa...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 39c289ac7a07dc0fc2754ae5d84f7d0aaed06298
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Wed Jan 20 20:46:54 2021 -0600

    GROOVY-9902: STC: allow method checking with partial generic information
---
 .../java/org/codehaus/groovy/ast/GenericsType.java | 16 ++++-----
 .../transform/stc/StaticTypeCheckingSupport.java   |  5 +--
 src/test/groovy/bugs/Groovy6786Bug.groovy          | 39 +++++++++------------
 .../groovy/transform/stc/GenericsSTCTest.groovy    | 40 ++++++++++++++++++++++
 4 files changed, 65 insertions(+), 35 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/ast/GenericsType.java b/src/main/java/org/codehaus/groovy/ast/GenericsType.java
index 84f28f7..a1da7a6 100644
--- a/src/main/java/org/codehaus/groovy/ast/GenericsType.java
+++ b/src/main/java/org/codehaus/groovy/ast/GenericsType.java
@@ -374,15 +374,15 @@ public class GenericsType extends ASTNode {
                     GenericsTypeName gtn = new GenericsTypeName(redirectBoundType.getName());
                     match = name.equals(gtn);
                     if (!match) {
-                        GenericsType genericsType = boundPlaceHolders.get(gtn);
-                        if (genericsType != null) {
-                            if (genericsType.isPlaceholder()) {
+                        GenericsType boundGenericsType = boundPlaceHolders.get(gtn);
+                        if (boundGenericsType != null) {
+                            if (boundGenericsType.isPlaceholder()) {
                                 match = true;
-                            } else if (genericsType.isWildcard()) {
-                                if (genericsType.getUpperBounds() != null) { // multiple bounds not allowed for ?
-                                    match = redirectBoundType.isCompatibleWith(genericsType.getUpperBounds()[0]);
-                                } else if (genericsType.getLowerBound() != null) {
-                                    match = redirectBoundType.isCompatibleWith(genericsType.getLowerBound());
+                            } else if (boundGenericsType.isWildcard()) {
+                                if (boundGenericsType.getUpperBounds() != null) { // ? supports single bound only
+                                    match = classNodeType.isCompatibleWith(boundGenericsType.getUpperBounds()[0]);
+                                } else if (boundGenericsType.getLowerBound() != null) {
+                                    match = classNodeType.isCompatibleWith(boundGenericsType.getLowerBound());
                                 } else {
                                     match = true;
                                 }
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 5f48a92..2c3db53 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
@@ -1372,14 +1372,11 @@ public abstract class StaticTypeCheckingSupport {
     }
 
     protected static boolean typeCheckMethodsWithGenerics(final ClassNode receiver, final ClassNode[] argumentTypes, final MethodNode candidateMethod) {
-        if (isUsingUncheckedGenerics(receiver)) {
-            return true;
-        }
         boolean isExtensionMethod = candidateMethod instanceof ExtensionMethodNode;
         if (!isExtensionMethod
                 && receiver.isUsingGenerics()
                 && receiver.equals(CLASS_Type)
-                && !candidateMethod.getDeclaringClass().equals(receiver)) {
+                && !candidateMethod.getDeclaringClass().equals(CLASS_Type)) {
             return typeCheckMethodsWithGenerics(receiver.getGenericsTypes()[0].getType(), argumentTypes, candidateMethod);
         }
         // both candidate method and receiver have generic information so a check is possible
diff --git a/src/test/groovy/bugs/Groovy6786Bug.groovy b/src/test/groovy/bugs/Groovy6786Bug.groovy
index 44aeaa4..f125a79 100644
--- a/src/test/groovy/bugs/Groovy6786Bug.groovy
+++ b/src/test/groovy/bugs/Groovy6786Bug.groovy
@@ -18,24 +18,22 @@
  */
 package groovy.bugs
 
-import groovy.test.NotYetImplemented
 import groovy.transform.stc.StaticTypeCheckingTestCase
 
 class Groovy6786Bug extends StaticTypeCheckingTestCase {
-    
+
     void testGenericAddAll() {
         assertScript '''
-
             public class Class1<ENTITY> {
-            
+
                 Container<ENTITY> container;
-            
+
                 void refresh() {
                     def items = findAllItems();
-                    
+
                     container.addAll(items);
                 }
-            
+
                 Collection<ENTITY> findAllItems() {
                     return null;
                 }
@@ -44,32 +42,30 @@ class Groovy6786Bug extends StaticTypeCheckingTestCase {
                 void addAll(Collection<? extends ENTITY> collection);
             }
             new Class1()
-
         '''
     }
 
     void testGuavaCacheBuilderLikeGenerics() {
         assertScript '''
             class Class1 {
-            
                 protected LoadingCache<String, Integer> cache;
-            
+
                 Class1(CacheLoader<String, Integer> cacheLoader) {
                     this.cache = CacheBuilder.newBuilder().build(cacheLoader);
                 }
             }
-            
+
             class CacheLoader<K, V> {}
-            
+
             class LoadingCache<K, V> {}
-            
+
             class CacheBuilder<K, V> {
                 public static CacheBuilder<Object, Object> newBuilder() {
                     return new CacheBuilder<Object, Object>();
                 }
-            
+
                 public <K1 extends K, V1 extends V> LoadingCache<K1, V1> build(CacheLoader<? super K1, V1> loader) {
-                    return new LoadingCache<K1, V1>();  
+                    return new LoadingCache<K1, V1>();
                 }
             }
             new Class1(null)
@@ -83,9 +79,9 @@ class Groovy6786Bug extends StaticTypeCheckingTestCase {
                     return false;
                 }
             }
-            
+
             abstract class AbstractExtendedManager<T> extends AbstractManager<T> {}
-                        
+
             class ConcreteManager extends AbstractExtendedManager<String> {
                 @Override
                  protected boolean update(String item){
@@ -99,20 +95,18 @@ class Groovy6786Bug extends StaticTypeCheckingTestCase {
     void testIfWithInstanceOfAndAnotherConditionAfter() {
         assertScript '''
             class Class1 {
-            
-            
                 Class1() {
                     Object obj = null;
-                    
+
                     if(obj instanceof String && someCondition() && testMethod(obj)) {
                         println "Hello!"
                     }
                 }
-                
+
                 boolean someCondition() {
                     return true;
                 }
-                
+
                 boolean testMethod(String arg) {
                     return true;
                 }
@@ -120,5 +114,4 @@ class Groovy6786Bug extends StaticTypeCheckingTestCase {
             new Class1();
         '''
     }
-    
 }
diff --git a/src/test/groovy/transform/stc/GenericsSTCTest.groovy b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
index 5008fbf..9667da0 100644
--- a/src/test/groovy/transform/stc/GenericsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
@@ -1113,6 +1113,46 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
         ''', '#printEqual(T, java.util.List <T>) with arguments [int, java.util.List <java.lang.String>]'
     }
 
+    // GROOVY-9902
+    void testIncompatibleArgumentsForGenericArgument_IncludingDelegation() {
+        shouldFailWithMessages '''
+            class Holder<Unknown> {
+                TypedProperty<Number, Unknown> numberProperty = prop(Number)
+                TypedProperty<String, Unknown> stringProperty = prop(String)
+
+                def <T> TypedProperty<T, Unknown> prop(Class<T> clazz) {
+                    return new TypedProperty<T, Unknown>(clazz: clazz)
+                }
+
+                // Note: type argument of Holder cannot be supplied to value attribute of @DelegatesTo
+                def <T> T of(@DelegatesTo(value=Holder, strategy=Closure.DELEGATE_FIRST) Closure<T> c) {
+                    this.with(c)
+                }
+            }
+
+            class TypedProperty<X, Y> {
+                Class<X> clazz
+
+                void eq(X x) {
+                    assert x.class == clazz : "x.class is ${x.class} not ${clazz}"
+                }
+            }
+
+            void test(Holder<Object> h) {
+                h.stringProperty.eq("${0}") // STC error
+                h.of { // <-- 2nd type parameter discarded
+                    stringProperty.eq(1234) // expect STC error
+                    numberProperty.eq("xx") // expect STC error
+                }
+            }
+
+            test(new Holder<Object>())
+        ''',
+        'Cannot call TypedProperty <String, Object>#eq(java.lang.String) with arguments [groovy.lang.GString]',
+        'Cannot call TypedProperty <String, Unknown>#eq(java.lang.String) with arguments [int]',
+        'Cannot call TypedProperty <Number, Unknown>#eq(java.lang.Number) with arguments [java.lang.String]'
+    }
+
     void testGroovy5748() {
         assertScript '''
             interface IStack<T> {


[groovy] 02/02: GROOVY-9981: helper methods for where pos/neg zero should be treated equal (to help avoid potentially confusing cases and help with writing code that works across 3/4) (closes #1518)

Posted by pa...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 323df745468047c9d5b9690aaeea8daa1edb05cc
Author: Paul King <pa...@asert.com.au>
AuthorDate: Fri Mar 12 22:46:39 2021 +1000

    GROOVY-9981: helper methods for where pos/neg zero should be treated equal (to help avoid potentially confusing cases and help with writing code that works across 3/4) (closes #1518)
---
 .../groovy/runtime/DefaultGroovyMethods.java       | 26 ++++++++++++++++++++++
 .../groovy/runtime/NumberAwareComparator.java      | 20 +++++++++++++++++
 2 files changed, 46 insertions(+)

diff --git a/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java b/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
index 1187e4f..9f09699 100644
--- a/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
+++ b/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
@@ -16910,6 +16910,32 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
+     * Compares this object against the specified object returning the same result
+     * as {@link Float#equals(Object)} but returning true if this object
+     * and the specified object are both zero and negative zero respectively or vice versa.
+     *
+     * @since 3.0.8
+     */
+    public static boolean equalsIgnoreZeroSign(Float number, Object other) {
+        if (other instanceof Float && 0.0f == number && 0.0f == (Float) other)
+            return true;
+        return number.equals(other);
+    }
+
+    /**
+     * Compares this object against the specified object returning the same result
+     * as {@link Double#equals(Object)} but returning true if this object
+     * and the specified object are both zero and negative zero respectively or vice versa.
+     *
+     * @since 3.0.8
+     */
+    public static boolean equalsIgnoreZeroSign(Double number, Object other) {
+        if (other instanceof Double && 0.0d == number && 0.0d == (Double) other)
+            return true;
+        return number.equals(other);
+    }
+
+    /**
      * Round the value
      *
      * @param number a Float
diff --git a/src/main/java/org/codehaus/groovy/runtime/NumberAwareComparator.java b/src/main/java/org/codehaus/groovy/runtime/NumberAwareComparator.java
index 6a11b03..498a209 100644
--- a/src/main/java/org/codehaus/groovy/runtime/NumberAwareComparator.java
+++ b/src/main/java/org/codehaus/groovy/runtime/NumberAwareComparator.java
@@ -31,9 +31,29 @@ import java.util.Comparator;
  */
 public class NumberAwareComparator<T> implements Comparator<T>, Serializable {
     private static final long serialVersionUID = 9017657289076651660L;
+    private boolean ignoreZeroSign;
+
+    public NumberAwareComparator() {
+        this(false);
+    }
+
+    /**
+     * @since 3.0.8
+     */
+    public NumberAwareComparator(boolean ignoreZeroSign) {
+        this.ignoreZeroSign = ignoreZeroSign;
+    }
 
     public int compare(T o1, T o2) {
         try {
+            if (ignoreZeroSign) {
+                if (o1 instanceof Float && 0.0f == (Float) o1 && o2 instanceof Float && 0.0f == (Float) o2) {
+                    return 0;
+                }
+                if (o1 instanceof Double && 0.0d == (Double) o1 && o2 instanceof Double && 0.0d == (Double) o2) {
+                    return 0;
+                }
+            }
             return DefaultTypeTransformation.compareTo(o1, o2);
         } catch (ClassCastException | IllegalArgumentException | GroovyRuntimeException cce) {
             /* ignore */