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 2022/11/28 18:19:29 UTC
[groovy] branch GROOVY_3_0_X updated: GROOVY-10813: fix receiver distance, receiver static and extension order
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 192b5f5dd2 GROOVY-10813: fix receiver distance, receiver static and extension order
192b5f5dd2 is described below
commit 192b5f5dd296d4b61a6fc1c1b33737027223c930
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Mon Nov 28 11:41:20 2022 -0600
GROOVY-10813: fix receiver distance, receiver static and extension order
3_0_X backport
---
...StaticTypesMethodReferenceExpressionWriter.java | 189 ++---
.../transform/stc/MethodReferenceTest.groovy | 939 ++++++++++++---------
2 files changed, 619 insertions(+), 509 deletions(-)
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesMethodReferenceExpressionWriter.java b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesMethodReferenceExpressionWriter.java
index 6894b5cccb..6dfb345ae1 100644
--- a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesMethodReferenceExpressionWriter.java
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesMethodReferenceExpressionWriter.java
@@ -18,8 +18,6 @@
*/
package org.codehaus.groovy.classgen.asm.sc;
-import groovy.lang.Tuple;
-import groovy.lang.Tuple2;
import org.codehaus.groovy.ast.ASTNode;
import org.codehaus.groovy.ast.ClassHelper;
import org.codehaus.groovy.ast.ClassNode;
@@ -39,16 +37,14 @@ import org.codehaus.groovy.syntax.RuntimeParserException;
import org.codehaus.groovy.transform.sc.StaticCompilationMetadataKeys;
import org.codehaus.groovy.transform.stc.ExtensionMethodNode;
import org.codehaus.groovy.transform.stc.StaticTypesMarker;
+import org.objectweb.asm.Handle;
import org.objectweb.asm.Opcodes;
-import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
-import java.util.stream.Collectors;
-import static org.apache.groovy.ast.tools.ClassNodeUtils.addGeneratedMethod;
-import static org.codehaus.groovy.ast.tools.GeneralUtils.args;
-import static org.codehaus.groovy.ast.tools.GeneralUtils.block;
+import static java.util.Comparator.comparingInt;
+import static java.util.stream.Collectors.joining;
import static org.codehaus.groovy.ast.tools.GeneralUtils.callX;
import static org.codehaus.groovy.ast.tools.GeneralUtils.classX;
import static org.codehaus.groovy.ast.tools.GeneralUtils.ctorX;
@@ -114,21 +110,15 @@ public class StaticTypesMethodReferenceExpressionWriter extends MethodReferenceE
}
typeOrTargetRefType = methodRefMethod.getDeclaringClass();
- Expression classExpression = classX(typeOrTargetRefType);
- classExpression.setSourcePosition(typeOrTargetRef);
- typeOrTargetRef = classExpression;
+ typeOrTargetRef = makeClassTarget(typeOrTargetRefType, typeOrTargetRef);
}
- methodRefMethod.putNodeMetaData(ORIGINAL_PARAMETERS_WITH_EXACT_TYPE, parametersWithExactType);
-
if (!isClassExpression) {
- if (isConstructorReference) {
- // TODO: move the checking code to the parser
+ if (isConstructorReference) { // TODO: move this check to the parser
addFatalError("Constructor reference must be className::new", methodReferenceExpression);
} else if (methodRefMethod.isStatic()) {
- ClassExpression classExpression = classX(typeOrTargetRefType);
- classExpression.setSourcePosition(typeOrTargetRef);
- typeOrTargetRef = classExpression;
+ // "string"::valueOf refers to static method, so instance is superfluous
+ typeOrTargetRef = makeClassTarget(typeOrTargetRefType, typeOrTargetRef);
isClassExpression = true;
} else {
typeOrTargetRef.visit(controller.getAcg());
@@ -144,18 +134,24 @@ public class StaticTypesMethodReferenceExpressionWriter extends MethodReferenceE
referenceKind = Opcodes.H_INVOKEVIRTUAL;
}
- controller.getMethodVisitor().visitInvokeDynamicInsn(
- abstractMethod.getName(),
- createAbstractMethodDesc(functionalInterfaceType, typeOrTargetRef),
- createBootstrapMethod(classNode.isInterface(), false),
- createBootstrapMethodArguments(
- createMethodDescriptor(abstractMethod),
- referenceKind,
- isConstructorReference ? classNode : typeOrTargetRefType,
- methodRefMethod,
- false
- )
- );
+ String methodName = abstractMethod.getName();
+ String methodDesc = BytecodeHelper.getMethodDescriptor(functionalInterfaceType.redirect(),
+ isClassExpression ? Parameter.EMPTY_ARRAY : new Parameter[]{new Parameter(typeOrTargetRefType, "__METHODREF_EXPR_INSTANCE")});
+
+ methodRefMethod.putNodeMetaData(ORIGINAL_PARAMETERS_WITH_EXACT_TYPE, parametersWithExactType);
+ try {
+ Handle bootstrapMethod = createBootstrapMethod(classNode.isInterface(), false);
+ Object[] bootstrapArgs = createBootstrapMethodArguments(
+ createMethodDescriptor(abstractMethod),
+ referenceKind,
+ methodRefMethod.getDeclaringClass(),
+ methodRefMethod,
+ false
+ );
+ controller.getMethodVisitor().visitInvokeDynamicInsn(methodName, methodDesc, bootstrapMethod, bootstrapArgs);
+ } finally {
+ methodRefMethod.removeNodeMetaData(ORIGINAL_PARAMETERS_WITH_EXACT_TYPE);
+ }
if (isClassExpression) {
controller.getOperandStack().push(functionalInterfaceType);
@@ -167,40 +163,33 @@ public class StaticTypesMethodReferenceExpressionWriter extends MethodReferenceE
private void validate(final MethodReferenceExpression methodReference, final ClassNode targetType, final String methodName, final MethodNode methodNode, final Parameter[] samParameters, final ClassNode samReturnType) {
if (methodNode == null) {
String error = String.format("Failed to find the expected method[%s(%s)] in the type[%s]",
- methodName, Arrays.stream(samParameters).map(e -> e.getType().getText()).collect(Collectors.joining(",")), targetType.getText());
+ methodName, Arrays.stream(samParameters).map(e -> e.getType().getText()).collect(joining(",")), targetType.getText());
addFatalError(error, methodReference);
} else if (methodNode.isVoidMethod() && !samReturnType.equals(ClassHelper.VOID_TYPE)) {
addFatalError("Invalid return type: void is not convertible to " + samReturnType.getText(), methodReference);
- } else if (samParameters.length > 0 && isTypeReferingInstanceMethod(methodReference.getExpression(), methodNode) && !isAssignableTo(samParameters[0].getType(), targetType)) {
+ } else if (samParameters.length > 0 && isTypeReferringInstanceMethod(methodReference.getExpression(), methodNode) && !isAssignableTo(samParameters[0].getType(), targetType)) {
throw new RuntimeParserException("Invalid receiver type: " + samParameters[0].getType().getText() + " is not compatible with " + targetType.getText(), methodReference.getExpression());
}
}
private MethodNode addSyntheticMethodForDGSM(final MethodNode mn) {
Parameter[] parameters = removeFirstParameter(mn.getParameters());
- ArgumentListExpression args = args(parameters);
+ ArgumentListExpression args = new ArgumentListExpression(parameters);
args.getExpressions().add(0, nullX());
MethodCallExpression returnValue = callX(classX(mn.getDeclaringClass()), mn.getName(), args);
returnValue.putNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET, mn);
returnValue.setMethodTarget(mn);
- MethodNode delegateMethod = addGeneratedMethod(controller.getClassNode(),
- "dgsm$$" + mn.getParameters()[0].getType().getName().replace('.', '$') + "$$" + mn.getName(),
- Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC | Opcodes.ACC_FINAL | Opcodes.ACC_SYNTHETIC,
- mn.getReturnType(),
- parameters,
- ClassNode.EMPTY_ARRAY,
- block(returnS(returnValue))
- );
+ String methodName = "dgsm$$" + mn.getParameters()[0].getType().getName().replace('.', '$') + "$$" + mn.getName();
+ MethodNode delegateMethod = addSyntheticMethod(methodName, mn.getReturnType(), returnValue, parameters, mn.getExceptions());
delegateMethod.putNodeMetaData(StaticCompilationMetadataKeys.STATIC_COMPILE_NODE, Boolean.TRUE);
-
return delegateMethod;
}
- private MethodNode addSyntheticMethodForConstructorReference(final String syntheticMethodName, final ClassNode returnType, final Parameter[] parametersWithExactType) {
- ArgumentListExpression ctorArgs = args(parametersWithExactType);
+ private MethodNode addSyntheticMethodForConstructorReference(final String methodName, final ClassNode returnType, final Parameter[] parametersWithExactType) {
+ ArgumentListExpression ctorArgs = new ArgumentListExpression(parametersWithExactType);
Expression returnValue;
if (returnType.isArray()) {
@@ -211,32 +200,22 @@ public class StaticTypesMethodReferenceExpressionWriter extends MethodReferenceE
returnValue = ctorX(returnType, ctorArgs);
}
- MethodNode delegateMethod = addGeneratedMethod(controller.getClassNode(),
- syntheticMethodName,
- Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC | Opcodes.ACC_FINAL | Opcodes.ACC_SYNTHETIC,
- returnType,
- parametersWithExactType,
- ClassNode.EMPTY_ARRAY,
- block(returnS(returnValue))
- );
-
+ MethodNode delegateMethod = addSyntheticMethod(methodName, returnType, returnValue, parametersWithExactType, ClassNode.EMPTY_ARRAY);
// TODO: if StaticTypesMarker.DIRECT_METHOD_CALL_TARGET or
// OptimizingStatementWriter.StatementMeta.class metadatas
// can bet set for the ctorX above, then this can be TRUE:
delegateMethod.putNodeMetaData(StaticCompilationMetadataKeys.STATIC_COMPILE_NODE, Boolean.FALSE);
-
return delegateMethod;
}
- private String createAbstractMethodDesc(final ClassNode functionalInterfaceType, final Expression methodRef) {
- List<Parameter> methodReferenceSharedVariableList = new ArrayList<>();
-
- if (!(methodRef instanceof ClassExpression)) {
- prependParameter(methodReferenceSharedVariableList, "__METHODREF_EXPR_INSTANCE",
- controller.getTypeChooser().resolveType(methodRef, controller.getClassNode()));
- }
-
- return BytecodeHelper.getMethodDescriptor(functionalInterfaceType.redirect(), methodReferenceSharedVariableList.toArray(Parameter.EMPTY_ARRAY));
+ private MethodNode addSyntheticMethod(final String methodName, final ClassNode returnType, final Expression returnValue, final Parameter[] parameters, final ClassNode[] exceptions) {
+ return controller.getClassNode().addSyntheticMethod(
+ methodName,
+ Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC | Opcodes.ACC_FINAL,
+ returnType,
+ parameters,
+ exceptions,
+ returnS(returnValue));
}
private Parameter[] createParametersWithExactType(final MethodNode abstractMethod, final ClassNode[] inferredParamTypes) {
@@ -263,9 +242,9 @@ public class StaticTypesMethodReferenceExpressionWriter extends MethodReferenceE
private MethodNode findMethodRefMethod(final String methodName, final Parameter[] samParameters, final Expression typeOrTargetRef, final ClassNode typeOrTargetRefType) {
List<MethodNode> methods = findVisibleMethods(methodName, typeOrTargetRefType);
- return chooseMethodRefMethodCandidate(typeOrTargetRef, methods.stream().filter(method -> {
+ methods.removeIf(method -> {
Parameter[] parameters = method.getParameters();
- if (isTypeReferingInstanceMethod(typeOrTargetRef, method)) {
+ if (isTypeReferringInstanceMethod(typeOrTargetRef, method)) {
// there is an implicit parameter for "String::length"
ClassNode firstParamType = method.getDeclaringClass();
@@ -276,8 +255,29 @@ public class StaticTypesMethodReferenceExpressionWriter extends MethodReferenceE
parameters = plusOne;
}
- return parametersCompatible(samParameters, parameters);
- }).collect(Collectors.toList()));
+ return !parametersCompatible(samParameters, parameters);
+ });
+
+ return chooseMethodRefMethod(methods, typeOrTargetRef, typeOrTargetRefType);
+ }
+
+ private MethodNode chooseMethodRefMethod(final List<MethodNode> methods, final Expression typeOrTargetRef, final ClassNode typeOrTargetRefType) {
+ if (methods.isEmpty()) return null;
+ if (methods.size() == 1) return methods.get(0);
+ return methods.stream().max(comparingInt((MethodNode mn) -> {
+ int score = 9;
+ for (ClassNode cn = typeOrTargetRefType; cn != null && !cn.equals(mn.getDeclaringClass()); cn = cn.getSuperClass()) {
+ score -= 1;
+ }
+ if (score < 0) {
+ score = 0;
+ }
+ score *= 10;
+ if ((typeOrTargetRef instanceof ClassExpression) == isStaticMethod(mn)) {
+ score += 9;
+ }
+ return score;
+ }).thenComparing(StaticTypesMethodReferenceExpressionWriter::isExtensionMethod)).get();
}
private List<MethodNode> findVisibleMethods(final String name, final ClassNode type) {
@@ -298,57 +298,30 @@ public class StaticTypesMethodReferenceExpressionWriter extends MethodReferenceE
//--------------------------------------------------------------------------
- private static boolean isConstructorReference(final String methodRefName) {
- return "new".equals(methodRefName);
+ private static boolean isConstructorReference(final String name) {
+ return "new".equals(name);
}
- private static boolean isExtensionMethod(final MethodNode methodRefMethod) {
- return (methodRefMethod instanceof ExtensionMethodNode);
+ private static boolean isExtensionMethod(final MethodNode mn) {
+ return (mn instanceof ExtensionMethodNode);
}
- private static boolean isTypeReferingInstanceMethod(final Expression typeOrTargetRef, final MethodNode mn) {
- // class::instanceMethod
- return (typeOrTargetRef instanceof ClassExpression) && ((mn != null && !mn.isStatic())
- || (isExtensionMethod(mn) && !((ExtensionMethodNode) mn).isStaticExtension()));
+ private static boolean isStaticMethod(final MethodNode mn) {
+ return isExtensionMethod(mn) ? ((ExtensionMethodNode) mn).isStaticExtension() : mn.isStatic();
}
- private static Parameter[] removeFirstParameter(final Parameter[] parameters) {
- return Arrays.copyOfRange(parameters, 1, parameters.length);
+ private static boolean isTypeReferringInstanceMethod(final Expression typeOrTargetRef, final MethodNode mn) {
+ // class::instanceMethod
+ return (typeOrTargetRef instanceof ClassExpression) && (mn != null && !isStaticMethod(mn));
}
- /**
- * Choose the best method node for method reference.
- */
- private static MethodNode chooseMethodRefMethodCandidate(final Expression methodRef, final List<MethodNode> candidates) {
- if (1 == candidates.size()) return candidates.get(0);
-
- return candidates.stream()
- .map(e -> Tuple.tuple(e, matchingScore(e, methodRef)))
- .min((t1, t2) -> Integer.compare(t2.getV2(), t1.getV2()))
- .map(Tuple2::getV1)
- .orElse(null);
+ private static Expression makeClassTarget(final ClassNode target, final Expression source) {
+ Expression expression = classX(target);
+ expression.setSourcePosition(source);
+ return expression;
}
- private static Integer matchingScore(final MethodNode mn, final Expression typeOrTargetRef) {
- ClassNode typeOrTargetRefType = typeOrTargetRef.getType();
-
- int score = 9;
- for (ClassNode cn = mn.getDeclaringClass(); null != cn && !cn.equals(typeOrTargetRefType); cn = cn.getSuperClass()) {
- score -= 1;
- }
- if (score < 0) {
- score = 0;
- }
- score *= 10;
-
- if ((typeOrTargetRef instanceof ClassExpression) == mn.isStatic()) {
- score += 9;
- }
-
- if (isExtensionMethod(mn)) {
- score += 100;
- }
-
- return score;
+ private static Parameter[] removeFirstParameter(final Parameter[] parameters) {
+ return Arrays.copyOfRange(parameters, 1, parameters.length);
}
}
diff --git a/src/test/groovy/transform/stc/MethodReferenceTest.groovy b/src/test/groovy/transform/stc/MethodReferenceTest.groovy
index f72bfa1f73..bbca175e90 100644
--- a/src/test/groovy/transform/stc/MethodReferenceTest.groovy
+++ b/src/test/groovy/transform/stc/MethodReferenceTest.groovy
@@ -18,105 +18,95 @@
*/
package groovy.transform.stc
-import groovy.test.GroovyTestCase
import groovy.test.NotYetImplemented
+import org.junit.Test
+import static groovy.test.GroovyAssert.assertScript
import static groovy.test.GroovyAssert.isAtLeastJdk
+import static groovy.test.GroovyAssert.shouldFail
-final class MethodReferenceTest extends GroovyTestCase {
+final class MethodReferenceTest {
- // class::instanceMethod
- void testFunctionCI() {
- assertScript '''
- import java.util.stream.Collectors
+ private static final imports = '''\
+ import java.util.function.*
+ import java.util.stream.Collectors
+ import groovy.transform.CompileStatic
+ '''
- @groovy.transform.CompileStatic
- void p() {
+ @Test // class::instanceMethod
+ void testFunctionCI() {
+ assertScript imports + '''
+ @CompileStatic
+ void test() {
def result = [1, 2, 3].stream().map(Object::toString).collect(Collectors.toList())
assert result == ['1', '2', '3']
}
- p()
+ test()
'''
}
- // class::instanceMethod
+ @Test // class::instanceMethod
void testFunctionCI2() {
- assertScript '''
- import java.util.stream.Collectors
-
- @groovy.transform.CompileStatic
- void p() {
+ assertScript imports + '''
+ @CompileStatic
+ void test() {
def result = [1, 2, 3].stream().map(Integer::toString).collect(Collectors.toList())
assert result == ['1', '2', '3']
}
- p()
+ test()
'''
}
- // class::instanceMethod -- GROOVY-10047
+ @Test // class::instanceMethod -- GROOVY-10047
void testFunctionCI3() {
- assertScript '''
- import java.util.function.Function
- import static java.util.stream.Collectors.toMap
-
- @groovy.transform.CompileStatic
- void p() {
+ assertScript imports + '''
+ @CompileStatic
+ void test() {
List<String> list = ['a','bc','def']
Function<String,String> self = str -> str // help for toMap
- def map = list.stream().collect(toMap(self, String::length))
- assert map == [a: 1, bc: 2, 'def': 3]
+ def result = list.stream().collect(Collectors.toMap(self, String::length))
+ assert result == [a: 1, bc: 2, 'def': 3]
}
- p()
+ test()
'''
- assertScript '''
- import java.util.function.Function
- import static java.util.stream.Collectors.toMap
-
- @groovy.transform.CompileStatic
- void p() {
+ assertScript imports + '''
+ @CompileStatic
+ void test() {
List<String> list = ['a','bc','def']
// TODO: inference for T in toMap(Function<? super T,...>, Function<? super T,...>)
- def map = list.stream().collect(toMap(Function.<String>identity(), String::length))
- assert map == [a: 1, bc: 2, 'def': 3]
+ def result = list.stream().collect(Collectors.toMap(Function.<String>identity(), String::length))
+ assert result == [a: 1, bc: 2, 'def': 3]
}
- p()
+ test()
'''
}
- // class::instanceMethod
+ @Test // class::instanceMethod
void testFunctionCI4() {
- def err = shouldFail '''
- import static java.util.stream.Collectors.toList
-
- @groovy.transform.CompileStatic
- void p() {
- def result = [1, 2, 3].stream().map(String::toString).collect(toList())
- assert result == ["1", "2", "3"]
+ def err = shouldFail imports + '''
+ @CompileStatic
+ void test() {
+ [1, 2, 3].stream().map(String::toString).collect(Collectors.toList())
}
-
- p()
'''
assert err =~ /Invalid receiver type: java.lang.Integer is not compatible with java.lang.String/
}
- // class::instanceMethod -- GROOVY-9814
+ @Test // class::instanceMethod -- GROOVY-9814
void testFunctionCI5() {
- assertScript '''
- import java.util.function.*
- import groovy.transform.*
-
+ assertScript imports + '''
@CompileStatic
class One { String id }
@CompileStatic
class Two extends One { }
- @CompileStatic @Immutable(knownImmutableClasses=[Function])
+ @CompileStatic @groovy.transform.Immutable(knownImmutableClasses=[Function])
class FunctionHolder<T> {
Function<T, ?> extractor
@@ -133,203 +123,350 @@ final class MethodReferenceTest extends GroovyTestCase {
'''
}
- // class::instanceMethod -- GROOVY-9853
+ @NotYetImplemented
+ @Test // class::instanceMethod -- GROOVY-9813
void testFunctionCI6() {
- assertScript '''
- import java.util.function.*
- @groovy.transform.CompileStatic
+ String head = imports + '''
+ @CompileStatic
+ class C {
+ def <T> List<T> asList(T... a) {
+ return Arrays.asList(a)
+ }
+ static main(args) {
+ '''
+ String tail = '''
+ }
+ }
+ '''
+
+ shouldFail head + '''
+ Supplier<List> zero = C::asList
+ ''' + tail
+
+ assertScript head + '''
+ Function<C, List> one = C::asList
+ def list = one.apply(new C())
+ assert list.isEmpty()
+ ''' + tail
+
+ assertScript head + '''
+ BiFunction<C, Integer, List> two = C::asList
+ def list = two.apply(new C(),1)
+ assert list.size() == 1
+ assert list[0] == 1
+ ''' + tail
+ }
+
+ @Test // class::instanceMethod -- GROOVY-9853
+ void testFunctionCI7() {
+ assertScript imports + '''
+ @CompileStatic
void test() {
ToIntFunction<CharSequence> f = CharSequence::size
int size = f.applyAsInt("")
assert size == 0
}
+
test()
'''
- assertScript '''
- import java.util.function.*
- @groovy.transform.CompileStatic
+ assertScript imports + '''
+ @CompileStatic
void test() {
ToIntFunction<CharSequence> f = CharSequence::length
int length = f.applyAsInt("")
assert length == 0
}
+
test()
'''
- assertScript '''
- import java.util.function.*
- @groovy.transform.CompileStatic
+ assertScript imports + '''
+ @CompileStatic
void test() {
Function<CharSequence,Integer> f = CharSequence::length
Integer length = f.apply("")
assert length == 0
}
+
test()
'''
- assertScript '''
- import java.util.function.*
+ assertScript imports + '''
import java.util.stream.IntStream
- @groovy.transform.CompileStatic
+ @CompileStatic
void test() {
Function<CharSequence,IntStream> f = CharSequence::chars // default method
IntStream chars = f.apply("")
assert chars.count() == 0
}
+
test()
'''
if (!isAtLeastJdk('11.0')) return
- assertScript '''
- import java.util.function.*
- @groovy.transform.CompileStatic
+ assertScript imports + '''
+ @CompileStatic
void test() {
ToIntBiFunction<CharSequence,CharSequence> f = CharSequence::compare // static method
int result = f.applyAsInt("","")
assert result == 0
}
+
test()
'''
}
- // class::instanceMethod -- GROOVY-10734
- void testFunctionCI7() {
- assertScript '''
+ @Test // class::instanceMethod -- GROOVY-10734
+ void testFunctionCI8() {
+ assertScript imports + '''
class C {
String p
}
- @groovy.transform.CompileStatic
+
+ @CompileStatic
Map test(Collection<C> items) {
items.stream().collect(
- java.util.stream.Collectors.groupingBy(C::getP) // Failed to find the expected method[getP(Object)] in the type[C]
+ Collectors.groupingBy(C::getP) // Failed to find the expected method[getP(Object)] in the type[C]
)
}
+
def map = test([new C(p:'foo'), new C(p:'bar'), new C(p:'foo')])
assert map.foo.size() == 2
assert map.bar.size() == 1
'''
}
- // class::instanceMethod -- GROOVY-9974
+ @Test // class::instanceMethod -- GROOVY-9974
void testPredicateCI() {
- assertScript '''
- @groovy.transform.CompileStatic
+ assertScript imports + '''
+ @CompileStatic
void test(List<String> strings = ['']) {
strings.removeIf(String::isEmpty)
assert strings.isEmpty()
}
+
test()
'''
}
- // class::instanceMethod -- GROOVY-10791
+ @Test // class::instanceMethod -- GROOVY-10791
void testBiConsumerCI() {
- assertScript '''
- import java.util.function.*
- @groovy.transform.CompileStatic
+ assertScript imports + '''
+ @CompileStatic
def <T> void test(List<T> list, Consumer<? super T> todo) {
BiConsumer<List<T>, Consumer<? super T>> binder = List::forEach // default method of Iterator
binder.accept(list, todo)
}
+
test(['works']) { assert it == 'works' }
'''
}
- // class::instanceMethod
+ @Test // class::instanceMethod
void testBinaryOperatorCI() {
- assertScript '''
- @groovy.transform.CompileStatic
- void p() {
+ assertScript imports + '''
+ @CompileStatic
+ void test() {
def result = [1.0G, 2.0G, 3.0G].stream().reduce(0.0G, BigDecimal::add)
+ assert result == 6.0G
+ }
+
+ test()
+ '''
+ }
+
+ @NotYetImplemented
+ @Test // instance::instanceMethod -- GROOVY-9813
+ void testFunctionII() {
+ String asList = '''
+ def <T> List<T> asList(T... a) {
+ return Arrays.asList(a)
+ }
+ '''
+
+ assertScript imports + asList + '''
+ @CompileStatic
+ void test() {
+ Supplier<List> zero = this::asList
+ def list = zero.get()
+ assert list.isEmpty()
+ }
+
+ test()
+ '''
- assert 6.0G == result
+ assertScript imports + asList + '''
+ @CompileStatic
+ void test() {
+ Function<Integer, List> one = this::asList
+ def list = one.apply(1)
+ assert list.size() == 1
+ assert list[0] == 1
+ }
+
+ test()
+ '''
+
+ assertScript imports + asList + '''
+ @CompileStatic
+ void test() {
+ BiFunction<Integer, Integer, List> two = this::asList
+ def list = two.apply(2,3)
+ assert list.size() == 2
+ assert list[0] == 2
+ assert list[1] == 3
+ }
+
+ test()
+ '''
+
+ assertScript imports + asList + '''
+ @CompileStatic
+ void test() { def that = this
+ BiFunction<Integer, Integer, List> two = that::asList
+ def list = two.apply(2,3)
+ assert list.size() == 2
+ assert list[0] == 2
+ assert list[1] == 3
}
- p()
+ test()
'''
}
- // instance::instanceMethod
- void testBinaryOperatorII() {
- assertScript '''
- @groovy.transform.CompileStatic
- void p() {
- Adder adder = new Adder()
- def result = [1.0G, 2.0G, 3.0G].stream().reduce(0.0G, adder::add)
+ @NotYetImplemented
+ @Test // instance::instanceMethod -- GROOVY-10653
+ void testFunctionII2() {
+ assertScript imports + '''
+ class C {
+ List m(... args) {
+ [this,*args]
+ }
+ }
+
+ @CompileStatic
+ void test(C c) {
+ BiFunction<Integer, Integer, List> two = c::m
+ def list = two.apply(1,2)
+ assert list.size() == 3
+ assert list[0] == c
+ assert list[1] == 1
+ assert list[2] == 2
+ }
+
+ test(new C())
+ '''
+ }
- assert 6.0G == result
+ @NotYetImplemented
+ @Test // instance::instanceGroovyMethod -- GROOVY-10653
+ void testFunctionII3() {
+ assertScript imports + '''
+ @CompileStatic
+ int test(CharSequence chars) {
+ IntSupplier sizing = chars::size // from StringGroovyMethods
+ return sizing.getAsInt()
}
- p()
+ int size = test("foo")
+ assert size == 3
+ '''
+ }
+
+ @NotYetImplemented
+ @Test // instance::instanceMethod -- GROOVY-10057
+ void testPredicateII() {
+ assertScript imports + '''
+ Class c = Integer
+ Predicate p
+
+ p = c::isInstance
+ assert p.test(null) == false
+ assert p.test('xx') == false
+ assert p.test(1234) == true
+
+ p = c.&isInstance
+ assert p.test(null) == false
+ assert p.test('xx') == false
+ assert p.test(1234) == true
+
+ p = o -> c.isInstance(o)
+ assert p.test(null) == false
+ assert p.test('xx') == false
+ assert p.test(1234) == true
+
+ p = { c.isInstance(it) }
+ assert p.test(null) == false
+ assert p.test('xx') == false
+ assert p.test(1234) == true
+ '''
+ }
- @groovy.transform.CompileStatic
+ @Test // instance::instanceMethod
+ void testBinaryOperatorII() {
+ assertScript imports + '''
class Adder {
BigDecimal add(BigDecimal a, BigDecimal b) {
a.add(b)
}
}
- '''
- }
- // instance::instanceMethod
- void testBinaryOperatorII_COMPATIBLE() {
- assertScript '''
- @groovy.transform.CompileStatic
- void p() {
+ @CompileStatic
+ void test() {
Adder adder = new Adder()
def result = [1.0G, 2.0G, 3.0G].stream().reduce(0.0G, adder::add)
-
- assert 6.0G == result
+ assert result == 6.0G
}
- p()
+ test()
+ '''
+ }
- @groovy.transform.CompileStatic
+ @Test // instance::instanceMethod
+ void testBinaryOperatorII_COMPATIBLE() {
+ assertScript imports + '''
class Adder {
BigDecimal add(Number a, Number b) {
((BigDecimal) a).add((BigDecimal) b)
}
}
- '''
- }
-
- // expression::instanceMethod
- void testBinaryOperatorII_EXPRESSION() {
- assertScript '''
- @groovy.transform.CompileStatic
- void p() {
- def result = [1.0G, 2.0G, 3.0G].stream().reduce(0.0G, new Adder()::add)
- assert 6.0G == result
+ @CompileStatic
+ void test() {
+ Adder adder = new Adder()
+ def result = [1.0G, 2.0G, 3.0G].stream().reduce(0.0G, adder::add)
+ assert result == 6.0G
}
- p()
+ test()
+ '''
+ }
- @groovy.transform.CompileStatic
+ @Test // expression::instanceMethod
+ void testBinaryOperatorII_EXPRESSION() {
+ assertScript imports + '''
class Adder {
public BigDecimal add(BigDecimal a, BigDecimal b) {
a.add(b)
}
}
- '''
- }
-
- // expression::instanceMethod
- void testBinaryOperatorII_EXPRESSION2() {
- assertScript '''
- @groovy.transform.CompileStatic
- void p() {
- def result = [1.0G, 2.0G, 3.0G].stream().reduce(0.0G, new Adder().getThis()::add)
- assert new BigDecimal(6) == result
+ @CompileStatic
+ void test() {
+ def result = [1.0G, 2.0G, 3.0G].stream().reduce(0.0G, new Adder()::add)
+ assert result == 6.0G
}
- p()
+ test()
+ '''
+ }
- @groovy.transform.CompileStatic
+ @Test // expression::instanceMethod
+ void testBinaryOperatorII_EXPRESSION2() {
+ assertScript imports + '''
class Adder {
BigDecimal add(BigDecimal a, BigDecimal b) {
a.add(b)
@@ -339,65 +476,100 @@ final class MethodReferenceTest extends GroovyTestCase {
return this
}
}
- '''
- }
-
- // instance::staticMethod
- void testBinaryOperatorIS() {
- assertScript '''
- @groovy.transform.CompileStatic
- void p() {
- Adder adder = new Adder()
- def result = [1.0G, 2.0G, 3.0G].stream().reduce(0.0G, adder::add)
- assert 6.0G == result
+ @CompileStatic
+ void test() {
+ def result = [1.0G, 2.0G, 3.0G].stream().reduce(0.0G, new Adder().getThis()::add)
+ assert result == new BigDecimal(6)
}
- p()
+ test()
+ '''
+ }
- @groovy.transform.CompileStatic
+ @Test // instance::instanceMethod
+ void testBinaryOperatorII_RHS() {
+ assertScript imports + '''
class Adder {
- static BigDecimal add(BigDecimal a, BigDecimal b) {
+ BigDecimal add(BigDecimal a, BigDecimal b) {
a.add(b)
}
}
+
+ @CompileStatic
+ void test() {
+ Adder adder = new Adder()
+ BinaryOperator<BigDecimal> b = adder::add
+ def result = [1.0G, 2.0G, 3.0G].stream().reduce(0.0G, b)
+ assert result == 6.0G
+ }
+
+ test()
'''
}
- // expression::staticMethod
- void testBinaryOperatorIS_EXPRESSION() {
- assertScript '''
- @groovy.transform.CompileStatic
- void p() {
- def result = [1.0G, 2.0G, 3.0G].stream().reduce(0.0G, new Adder()::add)
+ @Test // expression::instanceMethod
+ void testBinaryOperatorII_RHS2() {
+ assertScript imports + '''
+ class Adder {
+ BigDecimal add(BigDecimal a, BigDecimal b) {
+ a.add(b)
+ }
+ }
- assert 6.0G == result
+ @CompileStatic
+ void test() {
+ BinaryOperator<BigDecimal> b = new Adder()::add
+ def result = [1.0G, 2.0G, 3.0G].stream().reduce(0.0G, b)
+ assert result == 6.0G
}
- p()
+ test()
+ '''
+ }
- @groovy.transform.CompileStatic
+ @Test // instance::staticMethod
+ void testBinaryOperatorIS() {
+ assertScript imports + '''
class Adder {
static BigDecimal add(BigDecimal a, BigDecimal b) {
a.add(b)
}
}
+
+ @CompileStatic
+ void test() {
+ Adder adder = new Adder()
+ def result = [1.0G, 2.0G, 3.0G].stream().reduce(0.0G, adder::add)
+ assert result == 6.0G
+ }
+
+ test()
'''
}
- // expression::staticMethod
- void testBinaryOperatorIS_EXPRESSION2() {
- assertScript '''
- @groovy.transform.CompileStatic
- void p() {
- def result = [1.0G, 2.0G, 3.0G].stream().reduce(0.0G, Adder.newInstance()::add)
+ @Test // expression::staticMethod
+ void testBinaryOperatorIS_EXPRESSION() {
+ assertScript imports + '''
+ class Adder {
+ static BigDecimal add(BigDecimal a, BigDecimal b) {
+ a.add(b)
+ }
+ }
- assert 6.0G == result
+ @CompileStatic
+ void test() {
+ def result = [1.0G, 2.0G, 3.0G].stream().reduce(0.0G, new Adder()::add)
+ assert result == 6.0G
}
- p()
+ test()
+ '''
+ }
- @groovy.transform.CompileStatic
+ @Test // expression::staticMethod
+ void testBinaryOperatorIS_EXPRESSION2() {
+ assertScript imports + '''
class Adder {
static BigDecimal add(BigDecimal a, BigDecimal b) {
a.add(b)
@@ -407,43 +579,48 @@ final class MethodReferenceTest extends GroovyTestCase {
new Adder()
}
}
+
+ @CompileStatic
+ void test() {
+ def result = [1.0G, 2.0G, 3.0G].stream().reduce(0.0G, Adder.newInstance()::add)
+ assert result == 6.0G
+ }
+
+ test()
'''
}
- // arrayClass::new
+ @Test // class::new
void testFunctionCN() {
- assertScript '''
- @groovy.transform.CompileStatic
- void p() {
- def result = [1, 2, 3].stream().toArray(Integer[]::new)
- assert result == new Integer[] { 1, 2, 3 }
+ assertScript imports + '''
+ @CompileStatic
+ void test() {
+ def result = ["1", "2", "3"].stream().map(Integer::new).collect(Collectors.toList())
+ assert result == [1, 2, 3]
}
- p()
+ test()
'''
}
- // class::new
+ @Test // class::new
void testFunctionCN2() {
- assertScript '''
- import static java.util.stream.Collectors.toList
-
- @groovy.transform.CompileStatic
- void p() {
- def result = ["1", "2", "3"].stream().map(Integer::new).collect(toList())
+ assertScript imports + '''
+ @CompileStatic
+ void test() {
+ Function<String, Integer> f = Integer::new
+ def result = ["1", "2", "3"].stream().map(f).collect(Collectors.toList())
assert result == [1, 2, 3]
}
- p()
+ test()
'''
}
- // class::new -- GROOVY-10033
+ @Test // class::new -- GROOVY-10033
void testFunctionCN3() {
- assertScript '''
- import java.util.function.Function
-
- @groovy.transform.CompileStatic
+ assertScript imports + '''
+ @CompileStatic
class C {
C(Function<String,Integer> f) {
def i = f.apply('42')
@@ -453,15 +630,14 @@ final class MethodReferenceTest extends GroovyTestCase {
new C(Integer::new)
}
}
+
C.test()
'''
}
- // class::new -- GROOVY-10033
+ @Test // class::new -- GROOVY-10033
void testFunctionCN4() {
- assertScript '''
- import java.util.function.Function
-
+ assertScript imports + '''
class A {
A(Function<A,B> f) {
B b = f.apply(this)
@@ -473,7 +649,7 @@ final class MethodReferenceTest extends GroovyTestCase {
assert a != null
}
}
- @groovy.transform.CompileStatic
+ @CompileStatic
class X extends A {
public X() {
super(Y::new)
@@ -489,41 +665,50 @@ final class MethodReferenceTest extends GroovyTestCase {
'''
}
- // class::staticMethod
- void testFunctionCS() {
- assertScript '''
- import static java.util.stream.Collectors.toList
+ @Test // arrayClass::new
+ void testIntFunctionCN() {
+ assertScript imports + '''
+ @CompileStatic
+ void test() {
+ IntFunction<Integer[]> f = Integer[]::new;
+ def result = [1, 2, 3].stream().toArray(f)
+ result == new Integer[] {1, 2, 3}
+ }
+
+ test()
+ '''
+ }
- @groovy.transform.CompileStatic
- void p() {
- def result = [1, -2, 3].stream().map(Math::abs).collect(toList())
+ @Test // class::staticMethod
+ void testFunctionCS() {
+ assertScript imports + '''
+ @CompileStatic
+ void test() {
+ def result = [1, -2, 3].stream().map(Math::abs).collect(Collectors.toList())
assert [1, 2, 3] == result
}
- p()
+ test()
'''
}
- // class::staticMethod
+ @Test // class::staticMethod
void testFunctionCS2() {
- assertScript '''
- import java.util.function.Function
- import static java.util.stream.Collectors.toMap
-
- @groovy.transform.CompileStatic
- void p() {
+ assertScript imports + '''
+ @CompileStatic
+ void test() {
List<String> list = ['x','y','z']
- def map = list.stream().collect(toMap(Function.identity(), Collections::singletonList))
+ def map = list.stream().collect(Collectors.toMap(Function.identity(), Collections::singletonList))
assert map == [x: ['x'], y: ['y'], z: ['z']]
}
- p()
+ test()
'''
}
- // class::staticMethod -- GROOVY-9799
+ @Test // class::staticMethod -- GROOVY-9799
void testFunctionCS3() {
- assertScript '''
+ assertScript imports + '''
class C {
String x
}
@@ -535,7 +720,7 @@ final class MethodReferenceTest extends GroovyTestCase {
}
}
- @groovy.transform.CompileStatic
+ @CompileStatic
def test(C c) {
Optional.of(c).map(D::from).get()
}
@@ -545,81 +730,78 @@ final class MethodReferenceTest extends GroovyTestCase {
'''
}
- // class::staticMethod
+ @Test // class::staticMethod
void testFunctionCS4() {
- assertScript '''
- import java.util.function.Function
- import java.util.stream.Collectors
-
- @groovy.transform.CompileStatic
- void p() {
+ assertScript imports + '''
+ @CompileStatic
+ void test() {
Function<Integer, Integer> f = Math::abs
def result = [1, -2, 3].stream().map(f).collect(Collectors.toList())
assert [1, 2, 3] == result
}
- p()
+ test()
'''
}
- // class::staticMethod
+ @Test // class::staticMethod
void testFunctionCS5() {
- assertScript '''
- import java.util.stream.Collectors
-
- @groovy.transform.CompileStatic
- void p() {
+ 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 result = [1, -2, 3].stream().map(f).collect(Collectors.toList())
assert [1, 2, 3] == result
}
- p()
+ test()
'''
}
- // class::staticMethod -- GROOVY-9813
@NotYetImplemented
+ @Test // class::staticMethod -- GROOVY-9813
void testFunctionCS6() {
- assertScript '''
- @groovy.transform.CompileStatic
- void p() {
- java.util.function.Supplier<List> zero = Arrays::asList
+ assertScript imports + '''
+ @CompileStatic
+ void test() {
+ Supplier<List> zero = Arrays::asList
def list = zero.get()
assert list.isEmpty()
}
- p()
+ test()
'''
- assertScript '''
- @groovy.transform.CompileStatic
- void p() {
- java.util.function.Function<Integer, List> one = Arrays::asList
+
+ assertScript imports + '''
+ @CompileStatic
+ void test() {
+ Function<Integer, List> one = Arrays::asList
def list = one.apply(1)
assert list.size() == 1
assert list[0] == 1
}
- p()
+ test()
'''
- assertScript '''
- @groovy.transform.CompileStatic
- void p() {
- java.util.function.BiFunction<Integer, Integer, List> two = Arrays::asList
+
+ assertScript imports + '''
+ @CompileStatic
+ void test() {
+ BiFunction<Integer, Integer, List> two = Arrays::asList
def list = two.apply(2,3)
assert list.size() == 2
assert list[0] == 2
assert list[1] == 3
}
- p()
+ test()
'''
}
- // class::staticMethod -- GROOVY-10807
+ @Test // class::staticMethod -- GROOVY-10807
void testFunctionCS7() {
- assertScript '''
- @groovy.transform.CompileStatic
+ assertScript imports + '''
+ @CompileStatic
class C {
public static Comparator<String> c = Comparator.<String,String>comparing(C::m)
static String m(String string) {
@@ -634,11 +816,11 @@ final class MethodReferenceTest extends GroovyTestCase {
'''
}
- // class::staticMethod
@NotYetImplemented
+ @Test // class::staticMethod
void testFunctionCS8() {
- assertScript '''
- @groovy.transform.CompileStatic
+ assertScript imports + '''
+ @CompileStatic
class C {
public static Comparator<String> c = Comparator.comparing(C::m)
static String m(String string) {
@@ -653,157 +835,51 @@ final class MethodReferenceTest extends GroovyTestCase {
'''
}
- // instance::instanceMethod
- void testBinaryOperatorII_RHS() {
- assertScript '''
- import java.util.function.BinaryOperator
-
- @groovy.transform.CompileStatic
- void p() {
- Adder adder = new Adder()
- BinaryOperator<BigDecimal> b = adder::add
- def result = [1.0G, 2.0G, 3.0G].stream().reduce(0.0G, b)
-
- assert 6.0G == result
- }
-
- p()
-
- @groovy.transform.CompileStatic
- class Adder {
- BigDecimal add(BigDecimal a, BigDecimal b) {
- a.add(b)
- }
- }
- '''
- }
-
- // expression::instanceMethod
- void testBinaryOperatorII_RHS2() {
- assertScript '''
- import java.util.function.BinaryOperator
-
- @groovy.transform.CompileStatic
- void p() {
- BinaryOperator<BigDecimal> b = new Adder()::add
- def result = [1.0G, 2.0G, 3.0G].stream().reduce(0.0G, b)
-
- assert 6.0G == result
- }
-
- p()
-
- @groovy.transform.CompileStatic
- class Adder {
- BigDecimal add(BigDecimal a, BigDecimal b) {
- a.add(b)
- }
- }
- '''
- }
-
- // class::new
- void testFunctionCN_RHS() {
- assertScript '''
- import java.util.function.Function
- import java.util.stream.Collectors
-
- @groovy.transform.CompileStatic
- void p() {
- Function<String, Integer> f = Integer::new
- assert [1, 2, 3] == ["1", "2", "3"].stream().map(f).collect(Collectors.toList())
- }
-
- p()
- '''
- }
-
- // arrayClass::new
- void testIntFunctionCN_RHS() {
- assertScript '''
- import java.util.function.IntFunction
- import java.util.stream.Stream
-
- @groovy.transform.CompileStatic
- void p() {
- IntFunction<Integer[]> f = Integer[]::new
- assert new Integer[] { 1, 2, 3 } == [1, 2, 3].stream().toArray(f)
- }
-
- p()
- '''
- }
-
- // class::instanceMethod
- void testFunctionCI_WRONGTYPE() {
- def err = shouldFail '''
- import java.util.stream.Collectors
-
- @groovy.transform.CompileStatic
- void p() {
- def result = [1, 2, 3].stream().map(String::toString).collect(Collectors.toList())
- assert 3 == result.size()
- assert ['1', '2', '3'] == result
- }
-
- p()
- '''
- assert err =~ /Invalid receiver type: java.lang.Integer is not compatible with java.lang.String/
- }
-
- // class::instanceMethod, actually class::staticMethod
+ @Test // class::instanceGroovyMethod
void testFunctionCI_DGM() {
- assertScript '''
- import java.util.stream.Collectors
-
- @groovy.transform.CompileStatic
- void p() {
+ assertScript imports + '''
+ @CompileStatic
+ void test() {
def result = ['a', 'ab', 'abc'].stream().map(String::size).collect(Collectors.toList())
assert [1, 2, 3] == result
}
- p()
+ test()
'''
}
- // class::staticMethod
+ @Test // class::staticGroovyMethod
void testFunctionCS_DGSM() {
- assertScript '''
- import java.util.stream.Collectors
-
- @groovy.transform.CompileStatic
- void p() {
+ assertScript imports + '''
+ @CompileStatic
+ void test() {
def result = [{}, {}, {}].stream().map(Thread::startDaemon).collect(Collectors.toList())
assert result.every(e -> e instanceof Thread)
}
- p()
+ test()
'''
}
- // class::instanceMethod
+ @Test // class::instanceGroovyMethod
void testFunctionCI_SHADOW_DGM() {
- assertScript '''
- import java.util.stream.Collectors
-
- @groovy.transform.CompileStatic
- void p() {
+ assertScript imports + '''
+ @CompileStatic
+ void test() {
def result = [[a:1], [b:2], [c:3]].stream().map(Object::toString).collect(Collectors.toList())
- assert 3 == result.size()
- assert ['[a:1]', '[b:2]', '[c:3]'] == result
+ assert result.size() == 3
+ assert result == ['[a:1]', '[b:2]', '[c:3]']
}
- p()
+ test()
'''
}
- // class::staticMethod
+ @Test // class::staticGroovyMethod
void testFunctionCS_MULTI_DGSM() {
- assertScript '''
- import java.util.stream.Collectors
-
- @groovy.transform.CompileStatic
- void p() {
+ assertScript imports + '''
+ @CompileStatic
+ void test() {
def result = [{}, {}, {}].stream().map(Thread::startDaemon).collect(Collectors.toList())
assert result.every(e -> e instanceof Thread)
@@ -811,41 +887,106 @@ final class MethodReferenceTest extends GroovyTestCase {
assert result.every(e -> e instanceof Thread)
}
- p()
+ test()
'''
}
- // class::unknown
+ @Test
void testMethodNotFound1() {
- def err = shouldFail '''
- @groovy.transform.CompileStatic
- void p() {
+ def err = shouldFail imports + '''
+ @CompileStatic
+ void test() {
[1.0G, 2.0G, 3.0G].stream().reduce(0.0G, BigDecimal::addx)
}
'''
- assert err.contains('Failed to find the expected method[addx(java.math.BigDecimal,java.math.BigDecimal)] in the type[java.math.BigDecimal]')
+ assert err.message.contains('Failed to find the expected method[addx(java.math.BigDecimal,java.math.BigDecimal)] in the type[java.math.BigDecimal]')
}
- // GROOVY-9463
+ @Test // GROOVY-9463
void testMethodNotFound2() {
- def err = shouldFail '''
- import java.util.function.Function
-
- @groovy.transform.CompileStatic
- void p() {
+ def err = shouldFail imports + '''
+ @CompileStatic
+ void test() {
Function<String,String> reference = String::toLowerCaseX
}
'''
- assert err.contains('Failed to find the expected method[toLowerCaseX(java.lang.String)] in the type[java.lang.String]')
+ assert err.message.contains('Failed to find the expected method[toLowerCaseX(java.lang.String)] in the type[java.lang.String]')
}
- // GROOVY-10742
- void testVoidMethodSelection() {
- def err = shouldFail '''
- import java.util.function.Function
+ @NotYetImplemented
+ @Test // GROOVY-10714
+ void testMethodSelection() {
+ assertScript imports + '''
+ class C {
+ String which
+ void m(int i) { which = 'int' }
+ void m(Number n) { which = 'Number' }
+ }
+ interface I {
+ I andThen(Consumer<? super Number> c)
+ I andThen(BiConsumer<? super Number, ?> bc)
+ }
+ @CompileStatic
+ void test(I i, C c) {
+ i = i.andThen(c::m) // "andThen" is ambiguous unless parameters of "m" overloads are taken into account
+ }
- void foo(bar) { }
- @groovy.transform.CompileStatic
+ C x= new C()
+ test(new I() {
+ I andThen(Consumer<? super Number> c) {
+ c.accept(42)
+ return this
+ }
+ I andThen(BiConsumer<? super Number, ?> bc) {
+ bc.accept(42, null)
+ return this
+ }
+ }, x)
+ assert x.which == 'Number'
+ '''
+ }
+
+ @Test // GROOVY-10813
+ void testMethodSelection2() {
+ for (spec in ['', '<?>', '<Object>', '<? extends Object>', '<? super String>']) {
+ assertScript imports + """
+ @CompileStatic
+ void test() {
+ Consumer$spec c = this::print // overloads in Script and DefaultGroovyMethods
+ c.accept('hello world!')
+ }
+
+ test()
+ """
+ }
+ for (spec in ['', '<?,?>', '<?,Object>', '<?,? extends Object>', '<?,? super String>']) {
+ assertScript imports + """
+ @CompileStatic
+ void test() {
+ BiConsumer$spec c = Object::print
+ c.accept(this, 'hello world!')
+ }
+
+ test()
+ """
+ }
+ assertScript imports + '''
+ @CompileStatic
+ void test() {
+ BiConsumer<Script,?> c = Script::print
+ c.accept(this, 'hello world!')
+ }
+
+ test()
+ '''
+ }
+
+ @Test // GROOVY-10742
+ void testIncompatibleReturnType() {
+ def err = shouldFail imports + '''
+ void foo(bar) {
+ }
+ @CompileStatic
void test() {
Function<Object,String> f = this::foo
}
@@ -853,16 +994,14 @@ final class MethodReferenceTest extends GroovyTestCase {
assert err =~ /Invalid return type: void is not convertible to java.lang.String/
}
- // GROOVY-10269
+ @Test // GROOVY-10269
void testNotFunctionalInterface() {
- def err = shouldFail '''
- import java.util.function.Consumer
-
+ def err = shouldFail imports + '''
void foo(Integer y) {
}
void bar(Consumer<Integer> x) {
}
- @groovy.transform.CompileStatic
+ @CompileStatic
void test() {
bar(this::foo)
def baz = { Consumer<Integer> x -> }
@@ -872,19 +1011,17 @@ final class MethodReferenceTest extends GroovyTestCase {
assert err =~ /The argument is a method reference, but the parameter type is not a functional interface/
}
- // GROOVY-10336
+ @Test // GROOVY-10336
void testNotFunctionalInterface2() {
- def err = shouldFail '''
- import java.util.function.Supplier
-
+ def err = shouldFail imports + '''
class C {
Integer m() { 1 }
}
- @groovy.transform.CompileStatic
+ @CompileStatic
void test() {
Supplier<Long> outer = () -> {
Closure<Long> inner = (Object o, Supplier<Integer> s) -> 2L
- inner(new Object(), new C()::m)
+ inner(new Object(), new C()::m) // TODO: resolve call(Object,Supplier<Integer>)
}
}
'''