This is an automated email from the ASF dual-hosted git repository.
emilles 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 8141efd4e6 GROOVY-4843, GROOVY-8560: box primitive array for spread
invocation
8141efd4e6 is described below
commit 8141efd4e60613709a0b03330d181f6fba75aebc
Author: Eric Milles <[email protected]>
AuthorDate: Sat Mar 15 12:50:33 2025 -0500
GROOVY-4843, GROOVY-8560: box primitive array for spread invocation
---
.../groovy/runtime/ScriptBytecodeAdapter.java | 3 +-
.../org/codehaus/groovy/vmplugin/v8/Selector.java | 35 +++++++++++++-------
src/test/groovy/SpreadArgTest.groovy | 17 +++++++++-
.../groovy/mock/interceptor/MockForJavaTest.groovy | 38 +++++++++++++++++-----
4 files changed, 71 insertions(+), 22 deletions(-)
diff --git
a/src/main/java/org/codehaus/groovy/runtime/ScriptBytecodeAdapter.java
b/src/main/java/org/codehaus/groovy/runtime/ScriptBytecodeAdapter.java
index 8d9b83679d..e73dd853cc 100644
--- a/src/main/java/org/codehaus/groovy/runtime/ScriptBytecodeAdapter.java
+++ b/src/main/java/org/codehaus/groovy/runtime/ScriptBytecodeAdapter.java
@@ -950,7 +950,8 @@ public class ScriptBytecodeAdapter {
} else if (value instanceof BaseStream) {
((BaseStream<?,?>)
value).iterator().forEachRemaining(ret::add);
} else if (value.getClass().isArray()) {
- Collections.addAll(ret,
DefaultTypeTransformation.primitiveArrayBox(value));
+ Collections.addAll(ret,
value.getClass().getComponentType().isPrimitive()
+ ? DefaultTypeTransformation.primitiveArrayBox(value) :
(Object[]) value);
} else {
String error = "Cannot spread the type " +
value.getClass().getName() + " with value " + value;
if (value instanceof Map) {
diff --git a/src/main/java/org/codehaus/groovy/vmplugin/v8/Selector.java
b/src/main/java/org/codehaus/groovy/vmplugin/v8/Selector.java
index ff81afc9cf..b9da452a7e 100644
--- a/src/main/java/org/codehaus/groovy/vmplugin/v8/Selector.java
+++ b/src/main/java/org/codehaus/groovy/vmplugin/v8/Selector.java
@@ -49,6 +49,7 @@ import
org.codehaus.groovy.runtime.metaclass.MethodMetaProperty;
import org.codehaus.groovy.runtime.metaclass.NewInstanceMetaMethod;
import org.codehaus.groovy.runtime.metaclass.NewStaticMetaMethod;
import org.codehaus.groovy.runtime.metaclass.ReflectionMetaMethod;
+import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
import org.codehaus.groovy.runtime.wrappers.Wrapper;
import org.codehaus.groovy.vmplugin.VMPlugin;
import org.codehaus.groovy.vmplugin.VMPluginFactory;
@@ -545,7 +546,7 @@ public abstract class Selector {
this.safeNavigation = safeNavigation && arguments[0] == null;
this.thisCall = thisCall;
this.spread = spreadCall;
- this.cache = !spread;
+ this.cache = !spreadCall;
if (LOG_ENABLED) {
StringBuilder msg =
@@ -786,8 +787,7 @@ public abstract class Selector {
Class<?>[] params = handle.type().parameterArray();
if (currentType != null) params = currentType.parameterArray();
if (!isVargs) {
- if (spread && useMetaClass) return;
- if (params.length == 2 && args.length == 1) {
+ if (!(spread && useMetaClass) && params.length == 2 &&
args.length == 1) {
handle = MethodHandles.insertArguments(handle, 1,
SINGLE_NULL_ARRAY);
}
return;
@@ -884,8 +884,9 @@ public abstract class Selector {
}
public void correctSpreading() {
- if (!spread || useMetaClass || skipSpreadCollector) return;
- handle = handle.asSpreader(Object[].class, args.length - 1);
+ if (spread && !useMetaClass && !skipSpreadCollector) {
+ handle = handle.asSpreader(Object[].class, args.length - 1);
+ }
}
/**
@@ -1081,12 +1082,24 @@ public abstract class Selector {
* number arguments.
*/
private static Object[] spread(final Object[] args, final boolean
spreadCall) {
- if (!spreadCall) return args;
- Object[] normalArguments = (Object[]) args[1];
- Object[] ret = new Object[normalArguments.length + 1];
- ret[0] = args[0];
- System.arraycopy(normalArguments, 0, ret, 1, ret.length - 1);
- return ret;
+ Object[] result = args;
+ if (spreadCall) {
+ Object[] arguments = (Object[]) args[1];
+ final int nArguments = arguments.length;
+
+ result = new Object[nArguments + 1];
+ result[0] = args[0]; // the receiver
+ System.arraycopy(arguments, 0, result, 1, nArguments);
+
+ // accommodate Object[] spreader m. handle
+ for (int i = 1; i <= nArguments; i += 1) {
+ var argumentType = result[i] != null ? result[i].getClass() :
Object.class;
+ if (argumentType.isArray() &&
argumentType.getComponentType().isPrimitive()) {
+ result[i] =
DefaultTypeTransformation.primitiveArrayBox(result[i]); // GROOVY-4843,
GROOVY-8560
+ }
+ }
+ }
+ return result;
}
/**
diff --git a/src/test/groovy/SpreadArgTest.groovy
b/src/test/groovy/SpreadArgTest.groovy
index c40e0fc645..b0ef57c8b6 100644
--- a/src/test/groovy/SpreadArgTest.groovy
+++ b/src/test/groovy/SpreadArgTest.groovy
@@ -18,7 +18,7 @@
*/
package groovy
-import org.junit.Test
+import org.junit.jupiter.api.Test
import static groovy.test.GroovyAssert.assertScript
@@ -52,6 +52,21 @@ final class SpreadArgTest {
'''
}
+ // GROOVY-8560
+ @Test
+ void testSpreadArray2() {
+ assertScript '''
+ def f(byte[] bytes) {
+ assert bytes.length == 2
+ }
+
+ def ba = new byte[]{0, 0}
+ def oa = new Object[]{ba}
+ f(oa[0])
+ f( *oa )
+ '''
+ }
+
// GROOVY-11186
@Test
void testSpreadOther() {
diff --git a/src/test/groovy/mock/interceptor/MockForJavaTest.groovy
b/src/test/groovy/mock/interceptor/MockForJavaTest.groovy
index 40d2e3c978..e3b2a049a9 100644
--- a/src/test/groovy/mock/interceptor/MockForJavaTest.groovy
+++ b/src/test/groovy/mock/interceptor/MockForJavaTest.groovy
@@ -18,20 +18,22 @@
*/
package groovy.mock.interceptor
-import groovy.test.GroovyTestCase
+import org.junit.jupiter.api.Test
-class MockForJavaTest extends GroovyTestCase {
+final class MockForJavaTest {
+
+ @Test
void testIterator() {
def iteratorContext = new MockFor(Iterator)
iteratorContext.demand.hasNext() { true }
iteratorContext.demand.hasNext() { true }
iteratorContext.demand.hasNext() { false }
def iterator = iteratorContext.proxyDelegateInstance()
- iteratorContext.demand.next() { "foo" }
+ iteratorContext.demand.next() { 'foo' }
def iterator2 = iteratorContext.proxyDelegateInstance()
assert new IteratorCounter().count(iterator2) == 2
- assert iterator2.next() == "foo"
+ assert iterator2.next() == 'foo'
iteratorContext.verify(iterator2)
assert new IteratorCounter().count(iterator) == 2
@@ -45,13 +47,31 @@ class MockForJavaTest extends GroovyTestCase {
iteratorContext.verify(iterator3)
}
+ // GROOVY-4843
+ @Test
+ void testStream() {
+ def streamContext = new MockFor(FileInputStream)
+ streamContext.demand.read(1..1) { byte[] b ->
+ b[0] = 1
+ b[1] = 2
+ return 2
+ }
+ def p = System.getProperty('os.name').contains('Windows') ? 'NUL' :
'/dev/null'
+ def s = streamContext.proxyDelegateInstance(p)
+ byte[] buffer = new byte[2]
+ assert s.read(buffer) == 2
+ assert buffer[0] == 1
+ assert buffer[1] == 2
+ streamContext.verify(s)
+ }
+
+ @Test
void testString() {
def stringContext = new MockFor(String)
- stringContext.demand.endsWith(2..2) { String arg -> arg == "foo" }
+ stringContext.demand.endsWith(2..2) { String arg -> arg == 'foo' }
def s = stringContext.proxyDelegateInstance()
- assert !s.endsWith("bar")
- assert s.endsWith("foo")
+ assert !s.endsWith('bar')
+ assert s.endsWith('foo')
stringContext.verify(s)
}
-
-}
\ No newline at end of file
+}