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/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. *

diff --git a/src/main/org/codehaus/groovy/runtime/DefaultGroovyMethods.java b/src/main/org/codehaus/groovy/runtime/DefaultGroovyMethods.java index 5c83bbe970..cf75557a97 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); } /** @@ -5124,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 LinkedHashSet
+     * 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]
diff --git a/src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java b/src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
index df9b801be3..a530bdc7b1 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;
@@ -2883,6 +2884,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/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
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 {