You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by pa...@apache.org on 2023/01/17 22:30:50 UTC
[groovy] branch master updated: GROOVY-10905: Improve matching implicit arg closures to SAM types
This is an automated email from the ASF dual-hosted git repository.
paulk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/groovy.git
The following commit(s) were added to refs/heads/master by this push:
new e29b9288ee GROOVY-10905: Improve matching implicit arg closures to SAM types
e29b9288ee is described below
commit e29b9288ee10d6ebe0443722294021f64371fbad
Author: Paul King <pa...@asert.com.au>
AuthorDate: Mon Jan 16 18:52:51 2023 +1000
GROOVY-10905: Improve matching implicit arg closures to SAM types
---
.../codehaus/groovy/runtime/MetaClassHelper.java | 8 +++++++-
.../transform/stc/StaticTypeCheckingSupport.java | 10 ++++++++--
.../groovy/transform/stc/ClosuresSTCTest.groovy | 22 ++++++++++++++++++++++
3 files changed, 37 insertions(+), 3 deletions(-)
diff --git a/src/main/java/org/codehaus/groovy/runtime/MetaClassHelper.java b/src/main/java/org/codehaus/groovy/runtime/MetaClassHelper.java
index df51723ea2..3e4b3fec8d 100644
--- a/src/main/java/org/codehaus/groovy/runtime/MetaClassHelper.java
+++ b/src/main/java/org/codehaus/groovy/runtime/MetaClassHelper.java
@@ -346,7 +346,13 @@ public class MetaClassHelper {
Method sam;
for (Class<?> c = ReflectionCache.autoboxType(argument); c != null && c != parameterClass; c = c.getSuperclass()) {
if (c == Closure.class && parameterClass.isInterface() && (sam = getSAMMethod(parameterClass)) != null) {
- if (getParameterCount(argument) == sam.getParameterCount()) objectDistance -= 1; // GROOVY-9881
+ // In the case of multiple overloads, give preference to equal parameter count
+ // with fuzzy matching of length for implicit arg Closures
+ int paramCount = getParameterCount(argument);
+ int samParamCount = sam.getParameterCount();
+ if ((paramCount == samParamCount) || // GROOVY-9881
+ (paramCount == -1 && (samParamCount == 0 || samParamCount == 1))) // GROOVY-10905
+ objectDistance -= 1;
objectDistance += 5; // ahead of Object but behind GroovyObjectSupport
break;
}
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 1d37c913bb..e113687537 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
@@ -953,9 +953,15 @@ public abstract class StaticTypeCheckingSupport {
if (receiver.implementsInterface(compare)) {
return dist + getMaximumInterfaceDistance(receiver, compare);
} else if (receiver.equals(CLOSURE_TYPE) && (sam = findSAM(compare)) != null) {
- // GROOVY-9881: in case of multiple overloads, give preference to equal parameter count
+ // In the case of multiple overloads, give preference to equal parameter count
+ // with fuzzy matching of length for implicit arg Closures
Integer closureParamCount = receiver.getNodeMetaData(StaticTypesMarker.CLOSURE_ARGUMENTS);
- if (closureParamCount != null && closureParamCount == sam.getParameters().length) dist -= 1;
+ if (closureParamCount != null) {
+ int samParamCount = sam.getParameters().length;
+ if ((closureParamCount == samParamCount) || // GROOVY-9881
+ (closureParamCount == -1 && (samParamCount == 0 || samParamCount == 1))) // GROOVY-10905
+ dist -= 1;
+ }
return dist + 13; // GROOVY-9852: @FunctionalInterface vs Object
}
diff --git a/src/test/groovy/transform/stc/ClosuresSTCTest.groovy b/src/test/groovy/transform/stc/ClosuresSTCTest.groovy
index 570697e5c6..53b5bbf549 100644
--- a/src/test/groovy/transform/stc/ClosuresSTCTest.groovy
+++ b/src/test/groovy/transform/stc/ClosuresSTCTest.groovy
@@ -1047,4 +1047,26 @@ class ClosuresSTCTest extends StaticTypeCheckingTestCase {
'Cannot assign value of type java.lang.Class<java.lang.Integer> to variable of type int',
"named param 'bar' has type 'java.lang.Class<java.lang.Number>' but expected 'java.lang.Number'"
}
+
+ // GROOVY-10905
+ void testImplicitArgClosureMatchesSamMethodWithOneArg() {
+ assertScript '''
+ def method1(java.util.function.IntUnaryOperator unary) { '1a' }
+ def method1(java.util.function.IntBinaryOperator binary) { '1b' }
+ assert method1{ x -> } == '1a'
+ assert method1{ x, y -> } == '1b'
+ assert method1{ } == '1a'
+ '''
+ }
+
+ // GROOVY-10905
+ void testImplicitArgClosureMatchesSamMethodWithZeroArgs() {
+ assertScript '''
+ def method2(java.util.function.IntSupplier supplier) { '2a' }
+ def method2(java.util.function.IntBinaryOperator binary) { '2b' }
+ assert method2{ -> } == '2a'
+ assert method2{ x, y -> } == '2b'
+ assert method2{ } == '2a'
+ '''
+ }
}