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+ * // 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
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 {