From c215e5d31922f24b36a26daf123ef293752669bb Mon Sep 17 00:00:00 2001 From: Paul King Date: Thu, 4 Oct 2012 21:11:02 +1000 Subject: [PATCH 1/6] GROOVY-5739: performance problem in DefaultGroovyMethods.removeAll/retainAll (thanks to Adrian Nistor) --- .../org/codehaus/groovy/runtime/DefaultGroovyMethods.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/org/codehaus/groovy/runtime/DefaultGroovyMethods.java b/src/main/org/codehaus/groovy/runtime/DefaultGroovyMethods.java index 5c83bbe970..229474c295 100644 --- a/src/main/org/codehaus/groovy/runtime/DefaultGroovyMethods.java +++ b/src/main/org/codehaus/groovy/runtime/DefaultGroovyMethods.java @@ -3211,7 +3211,9 @@ public static boolean containsAll(Collection self, Object[] items) { * @since 1.7.2 */ public static boolean removeAll(Collection self, Object[] items) { - return self.removeAll(Arrays.asList(items)); + Collection pickFrom = new TreeSet(new NumberAwareComparator()); + pickFrom.addAll(Arrays.asList(items)); + return self.removeAll(pickFrom); } /** @@ -3229,7 +3231,9 @@ public static boolean removeAll(Collection self, Object[] items) { * @since 1.7.2 */ public static boolean retainAll(Collection self, Object[] items) { - return self.retainAll(Arrays.asList(items)); + Collection pickFrom = new TreeSet(new NumberAwareComparator()); + pickFrom.addAll(Arrays.asList(items)); + return self.retainAll(pickFrom); } /** From 78988fed1e2be1bfc64c7e1dd1c74edd9b11ea3a Mon Sep 17 00:00:00 2001 From: Paul King Date: Sat, 6 Oct 2012 14:15:03 +1000 Subject: [PATCH 2/6] GROOVY-5745: DGM should have a getAt method for Iterable --- .../groovy/runtime/DefaultGroovyMethods.java | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/main/org/codehaus/groovy/runtime/DefaultGroovyMethods.java b/src/main/org/codehaus/groovy/runtime/DefaultGroovyMethods.java index 229474c295..eea3d8f06e 100644 --- a/src/main/org/codehaus/groovy/runtime/DefaultGroovyMethods.java +++ b/src/main/org/codehaus/groovy/runtime/DefaultGroovyMethods.java @@ -5128,6 +5128,31 @@ public static T getAt(Iterator self, int idx) { return null; } + + /** + * Support the subscript operator for an Iterable. Typical usage: + *
+     * // custom Iterable example:
+     * class MyIterable implements Iterable {
+     *   Iterator iterator() { [1, 2, 3].iterator() }
+     * }
+     * def myIterable = new MyIterable()
+     * assert myIterable[1] == 2
+     *
+     * // Set example:
+     * def set = [1,2,3] as HashSet
+     * assert set[1] == 2
+     * 
+ * + * @param self an Iterable + * @param idx an index value (-self.size() <= idx < self.size()) but using -ve index values will be inefficient + * @return the value at the given index (after normalisation) or null if no corresponding value was found + * @since 2.1.0 + */ + public static T getAt(Iterable self, int idx) { + return getAt(self.iterator(), idx); + } + /** * A helper method to allow lists to work with subscript operators. *
def list = [2, 3]

From 0728bb83ece6187ec2a90c9442db143a41fac982 Mon Sep 17 00:00:00 2001
From: Paul King 
Date: Sat, 6 Oct 2012 15:34:33 +1000
Subject: [PATCH 3/6] GROOVY-5745: DGM should have a getAt method for Iterable

---
 src/main/org/codehaus/groovy/runtime/DefaultGroovyMethods.java | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/main/org/codehaus/groovy/runtime/DefaultGroovyMethods.java b/src/main/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
index eea3d8f06e..cf75557a97 100644
--- a/src/main/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
+++ b/src/main/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
@@ -5140,7 +5140,7 @@ public static  T getAt(Iterator self, int idx) {
      * assert myIterable[1] == 2
      *
      * // Set example:
-     * def set = [1,2,3] as HashSet
+     * def set = [1,2,3] as LinkedHashSet
      * assert set[1] == 2
      * 
* From 5478bc33bb848fa2d3dda430dcea2b335ab16539 Mon Sep 17 00:00:00 2001 From: Cedric Champeau Date: Wed, 10 Oct 2012 15:17:56 +0200 Subject: [PATCH 4/6] GROOVY-5748: STC - Cannot find method due to wrong return type inference --- .../stc/StaticTypeCheckingVisitor.java | 11 +++- .../transform/stc/GenericsSTCTest.groovy | 60 +++++++++++++++++++ 2 files changed, 70 insertions(+), 1 deletion(-) diff --git a/src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java b/src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java index eae815d37e..73898e7049 100644 --- a/src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java +++ b/src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java @@ -1311,7 +1311,8 @@ private ClassNode checkReturnType(final ReturnStatement statement) { ); virtualDecl.setSourcePosition(statement); virtualDecl.visit(this); - inferred = (ClassNode) virtualDecl.getNodeMetaData(StaticTypesMarker.INFERRED_TYPE); + ClassNode newlyInferred = (ClassNode) virtualDecl.getNodeMetaData(StaticTypesMarker.INFERRED_TYPE); + if (!missesGenericsTypes(newlyInferred)) inferred = newlyInferred; } methodNode.putNodeMetaData(StaticTypesMarker.INFERRED_RETURN_TYPE, inferred); return inferred; @@ -2783,6 +2784,14 @@ private ClassNode inferReturnTypeGenerics(final ClassNode receiver, final Method } } + // GROOVY-5748 + if (returnType.isGenericsPlaceHolder()) { + GenericsType resolved = resolvedPlaceholders.get(returnType.getUnresolvedName()); + if (resolved!=null && !resolved.isPlaceholder() && !resolved.isWildcard()) { + return resolved.getType(); + } + } + GenericsType[] copy = new GenericsType[returnTypeGenerics.length]; for (int i = 0; i < copy.length; i++) { GenericsType returnTypeGeneric = returnTypeGenerics[i]; diff --git a/src/test/groovy/transform/stc/GenericsSTCTest.groovy b/src/test/groovy/transform/stc/GenericsSTCTest.groovy index 7e70c52757..27d5b49448 100644 --- a/src/test/groovy/transform/stc/GenericsSTCTest.groovy +++ b/src/test/groovy/transform/stc/GenericsSTCTest.groovy @@ -870,6 +870,66 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase { ''', '#printEqual(java.lang.Object , java.util.List ) with arguments [int, java.util.List ]' } + void testGroovy5748() { + assertScript ''' + interface IStack { + INonEmptyStack> push(T x) + } + + interface IEmptyStack extends IStack { + INonEmptyStack> push(T x) + } + + interface INonEmptyStack> extends IStack { + T getTop() + + TStackBeneath pop() + + INonEmptyStack> push(T x) + } + + class EmptyStack implements IEmptyStack { + INonEmptyStack> push(T x) { + new NonEmptyStack>(x, this) + } + } + + class NonEmptyStack> + implements INonEmptyStack { + private final TStackBeneath stackBeneathTop; + private final T top + + NonEmptyStack(T top, TStackBeneath stackBeneathTop) { + this.top = top + this.stackBeneathTop = stackBeneathTop + } + + T getTop() { + top + } + + TStackBeneath pop() { + stackBeneathTop + } + + INonEmptyStack> push(T x) { + new NonEmptyStack>(x, this) + } + } + + final IStack stack = new EmptyStack() + + def oneInteger = stack.push(1) + assert oneInteger.getTop() == 1 + + def twoIntegers = stack.push(1).push(2) + assert twoIntegers.getTop() == 2 + + def oneIntegerAgain = stack.push(1).push(2).pop() + assert oneIntegerAgain.getTop() == 1 // BOOM!!!! + ''' + } + static class MyList extends LinkedList {} public static class ClassA { From c5b708fc0e86062ea30fc2aeecb62364ff89dbda Mon Sep 17 00:00:00 2001 From: Paul King Date: Fri, 12 Oct 2012 17:23:41 +1000 Subject: [PATCH 5/6] typo --- src/main/groovy/transform/TupleConstructor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/groovy/transform/TupleConstructor.java b/src/main/groovy/transform/TupleConstructor.java index a5dc1b1cc1..06481954ee 100644 --- a/src/main/groovy/transform/TupleConstructor.java +++ b/src/main/groovy/transform/TupleConstructor.java @@ -47,7 +47,7 @@ * including all of the parameters - giving a no-arg constructor which can be used with the map-style naming conventions. *

* The order of parameters is given by the properties of any super classes with most super first - * (if {@code includeSuperProperties} is set) followed by the properties of the class followed by the + * (if {@code includeSuperProperties} is set) followed by the properties of the class followed * by the fields of the class (if {@code includeFields} is set). Within each grouping the order * is as attributes appear within the respective class. *

From d7a7c33f1dc5874872659fdeeab4bf968fd3b54e Mon Sep 17 00:00:00 2001 From: Paul King Date: Fri, 12 Oct 2012 19:04:43 +1000 Subject: [PATCH 6/6] GROOVY-5751: Adding milliseconds with TimeCategory gives incorrect toString --- src/main/groovy/time/BaseDuration.java | 7 +++++-- src/test/groovy/time/TimeCategoryTest.groovy | 7 +++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/main/groovy/time/BaseDuration.java b/src/main/groovy/time/BaseDuration.java index b6ebe63bb4..17e5972b86 100644 --- a/src/main/groovy/time/BaseDuration.java +++ b/src/main/groovy/time/BaseDuration.java @@ -104,8 +104,11 @@ public String toString() { if (this.hours != 0) buffer.add(this.hours + " hours"); if (this.minutes != 0) buffer.add(this.minutes + " minutes"); - if (this.seconds != 0 || this.millis != 0) - buffer.add((seconds == 0 ? (millis < 0 ? "-0" : "0") : seconds) + "." + StringGroovyMethods.padLeft("" + Math.abs(millis), 3, "0") + " seconds"); + if (this.seconds != 0 || this.millis != 0) { + int norm_millis = millis % 1000; + int norm_seconds = seconds + DefaultGroovyMethods.intdiv(millis - norm_millis, 1000).intValue(); + buffer.add((norm_seconds == 0 ? (norm_millis < 0 ? "-0" : "0") : norm_seconds) + "." + StringGroovyMethods.padLeft("" + Math.abs(norm_millis), 3, "0") + " seconds"); + } if (buffer.size() != 0) { return DefaultGroovyMethods.join(buffer, ", "); diff --git a/src/test/groovy/time/TimeCategoryTest.groovy b/src/test/groovy/time/TimeCategoryTest.groovy index db1e04df19..833545c235 100644 --- a/src/test/groovy/time/TimeCategoryTest.groovy +++ b/src/test/groovy/time/TimeCategoryTest.groovy @@ -218,4 +218,11 @@ class TimeCategoryTest extends GroovyTestCase { } } + void testToStringForOverflow() { + use(TimeCategory) { + def t = 800.milliseconds + 300.milliseconds + assert t.toString() == '1.100 seconds' + } + } + } \ No newline at end of file