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()