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 2023/12/11 18:10:37 UTC
(groovy) branch GROOVY_3_0_X updated: GROOVY-7992, GROOVY-9998, GROOVY-11024: override witness for `? super T`
This is an automated email from the ASF dual-hosted git repository.
emilles pushed a commit to branch GROOVY_3_0_X
in repository https://gitbox.apache.org/repos/asf/groovy.git
The following commit(s) were added to refs/heads/GROOVY_3_0_X by this push:
new e25fc2e751 GROOVY-7992, GROOVY-9998, GROOVY-11024: override witness for `? super T`
e25fc2e751 is described below
commit e25fc2e75165178e054d3384bd687ebf712588c8
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Sun Dec 10 12:42:07 2023 -0600
GROOVY-7992, GROOVY-9998, GROOVY-11024: override witness for `? super T`
3_0_X backport
---
.gitignore | 1 +
.../transform/stc/StaticTypeCheckingSupport.java | 84 ++++++++--------
.../transform/stc/StaticTypeCheckingVisitor.java | 111 +++++++++++----------
.../stc/DefaultGroovyMethodsSTCTest.groovy | 13 +++
.../groovy/transform/stc/GenericsSTCTest.groovy | 9 +-
.../transform/stc/MethodReferenceTest.groovy | 106 +++++++++++++-------
6 files changed, 189 insertions(+), 135 deletions(-)
diff --git a/.gitignore b/.gitignore
index 3516d1ee8d..6a2bc7b27a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,6 +6,7 @@ out/
*.DS_Store
*.class
+*.dat
*.swp
*~
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 3672629b3b..a0543ee3b4 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
@@ -1609,51 +1609,39 @@ public abstract class StaticTypeCheckingSupport {
static void applyGenericsConnections(final Map<GenericsTypeName, GenericsType> connections, final Map<GenericsTypeName, GenericsType> resolvedPlaceholders) {
if (connections == null || connections.isEmpty()) return;
- int count = 0;
- while (count++ < 10000) {
- boolean checkForMorePlaceholders = false;
- for (Map.Entry<GenericsTypeName, GenericsType> entry : resolvedPlaceholders.entrySet()) {
- // entry could be T=T, T=T extends U, T=V, T=String, T=? extends String, etc.
- GenericsType oldValue = entry.getValue();
- if (oldValue.isPlaceholder()) { // T=T or V, not T=String or ? ...
- GenericsTypeName name = new GenericsTypeName(oldValue.getName());
- GenericsType newValue = connections.get(name); // find "V" in T=V
- if (newValue == oldValue) continue;
- if (newValue == null) {
- newValue = connections.get(entry.getKey());
- if (newValue != null) { // GROOVY-10315, GROOVY-10317
- newValue = getCombinedGenericsType(oldValue, newValue);
- }
+ for (Map.Entry<GenericsTypeName, GenericsType> entry : resolvedPlaceholders.entrySet()) {
+ // entry could be T=T, T=T extends U, T=V, T=String, T=? extends String, etc.
+ GenericsType oldValue = entry.getValue();
+ if (oldValue.isPlaceholder()) { // T=T or V, not T=String or ? ...
+ GenericsTypeName name = new GenericsTypeName(oldValue.getName());
+ GenericsType newValue = connections.get(name); // find "V" in T=V
+ if (newValue == oldValue) continue;
+ if (newValue == null) {
+ newValue = connections.get(entry.getKey());
+ if (newValue != null) { // GROOVY-10315, GROOVY-10317
+ newValue = getCombinedGenericsType(oldValue, newValue);
}
- if (newValue == null) {
- entry.setValue(newValue = applyGenericsContext(connections, oldValue));
- checkForMorePlaceholders = checkForMorePlaceholders || !equalIncludingGenerics(oldValue, newValue);
- } else if (!newValue.isPlaceholder() || newValue != resolvedPlaceholders.get(name)) {
- // GROOVY-6787: Don't override the original if the replacement doesn't respect the bounds otherwise
- // the original bounds are lost, which can result in accepting an incompatible type as an argument!
- ClassNode replacementType = extractType(newValue);
- ClassNode suitabilityType = !replacementType.isGenericsPlaceHolder()
- ? replacementType : Optional.ofNullable(replacementType.getGenericsTypes())
- .map(gts -> extractType(gts[0])).orElse(replacementType.redirect());
-
- if (oldValue.isCompatibleWith(suitabilityType)) {
- if (newValue.isWildcard() && newValue.getLowerBound() == null && newValue.getUpperBounds() == null) {
- // GROOVY-9998: apply upper/lower bound for unknown
- entry.setValue(replacementType.asGenericsType());
- } else {
- entry.setValue(newValue);
- }
- if (!checkForMorePlaceholders && newValue.isPlaceholder()) {
- checkForMorePlaceholders = !equalIncludingGenerics(oldValue, newValue);
- }
+ }
+ if (newValue == null) {
+ entry.setValue(newValue = applyGenericsContext(connections, oldValue));
+ } else if (!newValue.isPlaceholder() || newValue != resolvedPlaceholders.get(name)) {
+ // GROOVY-6787: Don't override the original if the replacement doesn't respect the bounds otherwise
+ // the original bounds are lost, which can result in accepting an incompatible type as an argument!
+ ClassNode replacementType = extractType(newValue);
+ ClassNode suitabilityType = !replacementType.isGenericsPlaceHolder()
+ ? replacementType : Optional.ofNullable(replacementType.getGenericsTypes())
+ .map(gts -> extractType(gts[0])).orElse(replacementType.redirect());
+
+ if (oldValue.isCompatibleWith(suitabilityType)) {
+ if (newValue.isWildcard() && newValue.getLowerBound() == null && newValue.getUpperBounds() == null) {
+ // GROOVY-9998: apply upper/lower bound for unknown
+ entry.setValue(replacementType.asGenericsType());
+ } else {
+ entry.setValue(newValue);
}
}
}
}
- if (!checkForMorePlaceholders) break;
- }
- if (count >= 10000) {
- throw new GroovyBugError("unable to handle generics in " + resolvedPlaceholders + " with connections " + connections);
}
}
@@ -1796,9 +1784,17 @@ public abstract class StaticTypeCheckingSupport {
else if (ui.getUpperBounds()!=null) for (ClassNode ub: ui.getUpperBounds())
extractGenericsConnections(connections, ub, boundType); // GROOVY-10911
} else {
- extractGenericsConnections(connections, ui.getType(), boundType);
+ if (boundType.isGenericsPlaceHolder()) { // di like "? extends T" or "? super T"
+ // 6731,7992,8983,9998,10047,10499,10749,10765,...
+ ui = new GenericsType(ui.getType()); // erase type
+ if (lowerBound) ui.setWildcard(true); // binds weak
+ String placeholderName = boundType.getUnresolvedName();
+ connections.put(new GenericsTypeName(placeholderName), ui);
+ } else { // di like "? extends Iterable<T>" and ui like "List<Type>"
+ extractGenericsConnections(connections, ui.getType(), boundType);
+ }
}
- } else {
+ } else { // di like "List<T>", "List<Type>", "List<? extends T>", ...
extractGenericsConnections(connections, ui.getType(), di.getType());
}
}
@@ -1933,6 +1929,10 @@ public abstract class StaticTypeCheckingSupport {
}
static GenericsType getCombinedGenericsType(final GenericsType gt1, final GenericsType gt2) {
+ // GROOVY-7992, GROOVY-10765: "? super T" for gt1 or gt2?
+ if (isUnboundedWildcard(gt1) != isUnboundedWildcard(gt2))
+ return isUnboundedWildcard(gt2) ? gt1 : gt2;
+ // GROOVY-10315, GROOVY-10317, GROOVY-10339, ...
ClassNode cn1 = GenericsUtils.makeClassSafe0(CLASS_Type, gt1);
ClassNode cn2 = GenericsUtils.makeClassSafe0(CLASS_Type, gt2);
ClassNode lub = WideningCategories.lowestUpperBound(cn1, cn2);
diff --git a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
index cc30f5e3c8..26e042745a 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -5446,58 +5446,8 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
if (methodGenericTypes != null) {
Map<GenericsTypeName, GenericsType> resolvedPlaceholders = new HashMap<>();
- Parameter[] parameters = method.getParameters();
- final int nParameters = parameters.length;
-
- if (explicitTypeHints != null) { // resolve type parameters from type arguments
- int n = methodGenericTypes.length;
- if (n == explicitTypeHints.length) {
- for (int i = 0; i < n; i += 1) {
- resolvedPlaceholders.put(new GenericsTypeName(methodGenericTypes[i].getName()), explicitTypeHints[i]);
- }
- }
- } else if (nParameters > 0) { // resolve type parameters from call arguments
- List<Expression> expressions = InvocationWriter.makeArgumentList(arguments).getExpressions();
- int nArguments = expressions.size();
- boolean isVargs = isVargs(parameters);
- if (isVargs ? nArguments >= nParameters-1 : nArguments == nParameters) {
- for (int i = 0; i < nArguments; i += 1) {
- if (isNullConstant(expressions.get(i)))
- continue; // GROOVY-9984: skip null
- ClassNode argumentType = getDeclaredOrInferredType(expressions.get(i));
- ClassNode paramType = parameters[Math.min(i, nParameters-1)].getType();
- if (GenericsUtils.hasUnresolvedGenerics(paramType)) {
- // if supplying array param with multiple arguments or single non-array argument, infer using element type
- if (isVargs && (i >= nParameters || (i == nParameters-1 && (nArguments > nParameters || !argumentType.isArray())))) {
- paramType = paramType.getComponentType();
- }
- if (argumentType.isDerivedFrom(CLOSURE_TYPE)) {
- MethodNode sam = findSAM(paramType);
- if (sam != null) { // implicit closure coercion in action!
- argumentType = !paramType.isUsingGenerics() ? paramType
- : convertClosureTypeToSAMType(expressions.get(i), argumentType, sam, paramType,
- applyGenericsContextToParameterClass(resolvedPlaceholders, paramType));
- }
- }
- Map<GenericsTypeName, GenericsType> connections = new HashMap<>();
- extractGenericsConnections(connections, wrapTypeIfNecessary(argumentType), paramType);
- connections.forEach((name, type) -> resolvedPlaceholders.merge(name, type, StaticTypeCheckingSupport::getCombinedGenericsType));
- }
- }
- }
- // in case of "<T, U extends Type<T>>", we can learn about "T" from a resolved "U"
- extractGenericsConnectionsForBoundTypes(methodGenericTypes, resolvedPlaceholders);
- }
-
- for (GenericsType tp : methodGenericTypes) {
- // GROOVY-8409, GROOVY-10343, et al.: provide "no type witness" mapping for param
- resolvedPlaceholders.computeIfAbsent(new GenericsTypeName(tp.getName()), gtn -> {
- ClassNode[] bounds = applyGenericsContext(resolvedPlaceholders, tp.getUpperBounds());
- GenericsType gt = new GenericsType(tp.getType(), bounds, null);
- gt.putNodeMetaData(GenericsType.class, tp); // record origin
- return gt;
- });
- }
+ for (GenericsType gt : methodGenericTypes) resolvedPlaceholders.put(new GenericsTypeName(gt.getName()), gt);
+ applyGenericsConnections(extractGenericsConnectionsFromArguments(methodGenericTypes, method.getParameters(), arguments, explicitTypeHints), resolvedPlaceholders);
returnType = applyGenericsContext(resolvedPlaceholders, returnType);
}
@@ -5513,6 +5463,63 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
return returnType;
}
+ private Map<GenericsTypeName, GenericsType> extractGenericsConnectionsFromArguments(final GenericsType[] methodGenericTypes, final Parameter[] parameters, final Expression arguments, final GenericsType[] explicitTypeHints) {
+ Map<GenericsTypeName, GenericsType> resolvedPlaceholders = new HashMap<>();
+
+ if (explicitTypeHints != null) { // resolve type parameters from type arguments
+ int n = methodGenericTypes.length;
+ if (n == explicitTypeHints.length) {
+ for (int i = 0; i < n; i += 1) {
+ resolvedPlaceholders.put(new GenericsTypeName(methodGenericTypes[i].getName()), explicitTypeHints[i]);
+ }
+ }
+ } else if (parameters.length > 0) { // resolve type parameters from call arguments
+ List<Expression> expressions = InvocationWriter.makeArgumentList(arguments).getExpressions();
+ int nArguments = expressions.size();
+ int nParameters = parameters.length;
+ boolean isVargs = isVargs(parameters);
+ if (isVargs ? nArguments >= nParameters-1 : nArguments == nParameters) {
+ for (int i = 0; i < nArguments; i += 1) {
+ if (isNullConstant(expressions.get(i)))
+ continue; // GROOVY-9984: skip null
+ ClassNode argumentType = getDeclaredOrInferredType(expressions.get(i));
+ ClassNode paramType = parameters[Math.min(i, nParameters-1)].getType();
+ if (GenericsUtils.hasUnresolvedGenerics(paramType)) {
+ // if supplying array param with multiple arguments or single non-array argument, infer using element type
+ if (isVargs && (i >= nParameters || (i == nParameters-1 && (nArguments > nParameters || !argumentType.isArray())))) {
+ paramType = paramType.getComponentType();
+ }
+ if (argumentType.isDerivedFrom(CLOSURE_TYPE)) {
+ MethodNode sam = findSAM(paramType);
+ if (sam != null) { // implicit closure coercion in action!
+ argumentType = !paramType.isUsingGenerics() ? paramType
+ : convertClosureTypeToSAMType(expressions.get(i), argumentType, sam, paramType,
+ applyGenericsContextToParameterClass(resolvedPlaceholders, paramType));
+ }
+ }
+ Map<GenericsTypeName, GenericsType> connections = new HashMap<>();
+ extractGenericsConnections(connections, wrapTypeIfNecessary(argumentType), paramType);
+ connections.forEach((name, type) -> resolvedPlaceholders.merge(name, type, StaticTypeCheckingSupport::getCombinedGenericsType));
+ }
+ }
+ }
+ // in case of "<T, U extends Type<T>>", we can learn about "T" from a resolved "U"
+ extractGenericsConnectionsForBoundTypes(methodGenericTypes, resolvedPlaceholders);
+ }
+
+ for (GenericsType tp : methodGenericTypes) {
+ // GROOVY-8409, GROOVY-10343, et al.: provide "no type witness" mapping for param
+ resolvedPlaceholders.computeIfAbsent(new GenericsTypeName(tp.getName()), gtn -> {
+ ClassNode[] bounds = applyGenericsContext(resolvedPlaceholders, tp.getUpperBounds());
+ GenericsType gt = new GenericsType(tp.getType(), bounds, null);
+ gt.putNodeMetaData(GenericsType.class, tp); // record origin
+ return gt;
+ });
+ }
+
+ return resolvedPlaceholders;
+ }
+
/**
* Given method call like "m(Collections.emptyList())", the type of the call
* argument is {@code List<T>} without explicit type arguments. Knowing the
diff --git a/src/test/groovy/transform/stc/DefaultGroovyMethodsSTCTest.groovy b/src/test/groovy/transform/stc/DefaultGroovyMethodsSTCTest.groovy
index 83c3d7fb11..9385e95728 100644
--- a/src/test/groovy/transform/stc/DefaultGroovyMethodsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/DefaultGroovyMethodsSTCTest.groovy
@@ -218,6 +218,19 @@ class DefaultGroovyMethodsSTCTest extends StaticTypeCheckingTestCase {
'''
}
+ // GROOVY-7976, GROOVY-7992
+ void testSortMethodsWithComparatorAcceptingSuperclass() {
+ assertScript '''
+ List<Number> numbers = [2,1,3]
+ numbers.sort(new Comparator<Object>() {
+ int compare(o1, o2) {
+ o1.toString() <=> o2.toString()
+ }
+ })
+ assert numbers == [1,2,3]
+ '''
+ }
+
// GROOVY-8205
void testEachOnEnumValues() {
assertScript '''
diff --git a/src/test/groovy/transform/stc/GenericsSTCTest.groovy b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
index c1ca3b2c78..58f38bb74e 100644
--- a/src/test/groovy/transform/stc/GenericsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
@@ -798,7 +798,6 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
}
// GROOVY-7992
- @NotYetImplemented
void testReturnTypeInferenceWithMethodGenerics26() {
assertScript '''
List<String> strings = ['foo','bar','baz']
@@ -806,7 +805,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
@groovy.transform.ASTTest(phase=INSTRUCTION_SELECTION, value={
def type = node.getNodeMetaData(INFERRED_TYPE)
- assert type.toString(false) == 'java.util.List<java.lang.String>'
+ assert type.toString(false) == 'java.util.List <java.lang.String>'
})
def result = strings.sort(false, cmp) // List<T> sort(Iterable<T>,boolean,Comparator<? super T>)
assert result == ['bar', 'baz', 'foo']
@@ -2651,7 +2650,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
static <U> C<U> of(U item) {
new C<U>()
}
- def <V> C<V> map(A<? super T, ? super V> func) {
+ def <V> C<V> map(A<? super T, ? extends V> mapper) {
new C<V>()
}
}
@@ -4865,9 +4864,9 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
}
// GROOVY-9998
- @NotYetImplemented
void testContravariantMethodResolution2() {
- assertScript '''import groovy.transform.*
+ assertScript '''
+ import groovy.transform.*
@TupleConstructor(defaults=false)
class A {
diff --git a/src/test/groovy/transform/stc/MethodReferenceTest.groovy b/src/test/groovy/transform/stc/MethodReferenceTest.groovy
index 5e600732c9..92d1ba6417 100644
--- a/src/test/groovy/transform/stc/MethodReferenceTest.groovy
+++ b/src/test/groovy/transform/stc/MethodReferenceTest.groovy
@@ -24,7 +24,6 @@ import org.junit.Test
import static groovy.test.GroovyAssert.assertScript
import static groovy.test.GroovyAssert.isAtLeastJdk
import static groovy.test.GroovyAssert.shouldFail
-import static org.junit.Assume.assumeTrue
final class MethodReferenceTest {
@@ -293,6 +292,18 @@ final class MethodReferenceTest {
'''
}
+ @NotYetImplemented
+ @Test // class::instanceMethod -- GROOVY-11051
+ void testPredicateCI2() {
+ [['null','Empty'],['new Object()','Present']].each { value, which ->
+ assertScript """import java.util.concurrent.atomic.AtomicReference
+ def opt = new AtomicReference<Object>($value).stream()
+ .filter(AtomicReference::get).findFirst()
+ assert opt.is${which}()
+ """
+ }
+ }
+
@Test // class::instanceMethod -- GROOVY-10791
void testBiConsumerCI() {
assertScript imports + '''
@@ -306,6 +317,21 @@ final class MethodReferenceTest {
'''
}
+ @Test // instance::instanceMethod -- GROOVY-10974
+ void testBiConsumerII() {
+ assertScript imports + '''import java.util.stream.*
+ @CompileStatic
+ def test(DoubleStream x, ObjDoubleConsumer<Boolean> y, BiConsumer<Boolean, Boolean> z) {
+ def b = x.collect(() -> true, y::accept, z::accept) // b should infer as Boolean
+ // <R> R collect(Supplier<R>,ObjDoubleConsumer<R>,BiConsumer<R,R>)
+ Spliterator.OfDouble s_of_d = Arrays.spliterator(new double[0])
+ StreamSupport.doubleStream(s_of_d, b)
+ }
+
+ test(DoubleStream.of(0d), (Boolean b, double d) -> {}, (Boolean e, Boolean f) -> {})
+ '''
+ }
+
@Test // class::instanceMethod
void testBinaryOperatorCI() {
assertScript imports + '''
@@ -586,6 +612,25 @@ final class MethodReferenceTest {
'''
}
+ @NotYetImplemented
+ @Test // instance::instanceMethod -- GROOVY-11026
+ void testBiFunctionII() {
+ assertScript imports + '''
+ @groovy.transform.CompileDynamic
+ def <In,InOut> InOut m(BiFunction<In,InOut,InOut> beef) {
+ beef.apply(0,'boo')
+ }
+
+ @CompileStatic
+ String test(List<String> x) {
+ m(x::set) // NPE
+ }
+
+ String result = test(['foo','bar'])
+ assert result == 'foo'
+ '''
+ }
+
@Test // instance::instanceMethod
void testBinaryOperatorII() {
assertScript imports + '''
@@ -607,7 +652,7 @@ final class MethodReferenceTest {
}
@Test // instance::instanceMethod
- void testBinaryOperatorII_COMPATIBLE() {
+ void testBinaryOperatorII2() {
assertScript imports + '''
class Adder {
BigDecimal add(Number a, Number b) {
@@ -832,14 +877,14 @@ final class MethodReferenceTest {
}
@CompileStatic
class X extends A {
- public X() {
- super(Y::new)
- }
- private static class Y extends B {
- Y(A a) {
- super(a)
+ public X() {
+ super(Y::new)
+ }
+ private static class Y extends B {
+ Y(A a) {
+ super(a)
+ }
}
- }
}
new X()
@@ -897,29 +942,18 @@ final class MethodReferenceTest {
@Test // class::staticMethod
void testFunctionCS2() {
- assertScript imports + '''
- @CompileStatic
- def test(List<String> list) {
- list.stream().collect(Collectors.toMap(Function.identity(), Collections::singletonList))
- }
-
- assert test(['x','y','z']) == [x: ['x'], y: ['y'], z: ['z']]
- '''
- }
-
- @NotYetImplemented
- @Test // class::staticMethod -- GROOVY-11024
- void testFunctionCS2x() {
- assumeTrue(isAtLeastJdk('9.0'))
-
- assertScript imports + '''
- @CompileStatic
- def test(List<String> list) {
- list.stream().collect(Collectors.toMap(Function.identity(), List::of))
- }
+ def methods = ['Collections::singletonList']
+ if (isAtLeastJdk('9.0')) methods<<'List::of' // GROOVY-11024
+ for (makeList in methods) {
+ assertScript imports + """
+ @CompileStatic
+ def test(List<String> list) {
+ list.stream().collect(Collectors.toMap(Function.identity(), $makeList))
+ }
- assert test(['x','y','z']) == [x: ['x'], y: ['y'], z: ['z']]
- '''
+ assert test(['x','y','z']) == [x: ['x'], y: ['y'], z: ['z']]
+ """
+ }
}
@Test // class::staticMethod -- GROOVY-9799
@@ -965,7 +999,7 @@ final class MethodReferenceTest {
assertScript imports + '''
@CompileStatic
void test() {
- def f = Math::abs // No explicit type defined, so it is actually a method closure. We can make it smarter in a later version.
+ def f = Math::abs // No explicit type defined, so it is actually a method closure
def result = [1, -2, 3].stream().map(f).collect(Collectors.toList())
assert [1, 2, 3] == result
}
@@ -1033,7 +1067,7 @@ final class MethodReferenceTest {
}
@NotYetImplemented
- @Test // class::staticMethod
+ @Test // class::staticMethod -- GROOVY-10807
void testFunctionCS8() {
assertScript imports + '''
@CompileStatic
@@ -1089,7 +1123,7 @@ final class MethodReferenceTest {
@CompileStatic
void test() {
def result = [{}, {}, {}].stream().map(Thread::startDaemon).collect(Collectors.toList())
- assert result.every(e -> e instanceof Thread)
+ assert result.every { it instanceof Thread }
}
test()
@@ -1115,10 +1149,10 @@ final class MethodReferenceTest {
@CompileStatic
void test() {
def result = [{}, {}, {}].stream().map(Thread::startDaemon).collect(Collectors.toList())
- assert result.every(e -> e instanceof Thread)
+ assert result.every { it instanceof Thread }
result = [{}, {}, {}].stream().map(Thread::startDaemon).collect(Collectors.toList())
- assert result.every(e -> e instanceof Thread)
+ assert result.every { it instanceof Thread }
}
test()