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 5fbc4fbdb5 GROOVY-11186: iterable, iterator and stream as spread 
method argument(s)
5fbc4fbdb5 is described below

commit 5fbc4fbdb54450845db49c1a014e924dafd68fc1
Author: Eric Milles <eric.mil...@thomsonreuters.com>
AuthorDate: Sat Mar 9 16:25:44 2024 -0600

    GROOVY-11186: iterable, iterator and stream as spread method argument(s)
---
 .../groovy/runtime/ScriptBytecodeAdapter.java      |  18 ++--
 src/test/gls/invocation/MethodSelectionTest.groovy |  13 ---
 src/test/groovy/GroovyMethodsTest.groovy           |   6 +-
 src/test/groovy/SpreadArgTest.groovy               | 117 +++++++++++++++++++++
 src/test/groovy/SpreadDotTest.groovy               |  99 +++++++++--------
 src/test/groovy/bugs/Groovy9515.groovy             |  43 --------
 .../classgen/asm/sc/BugsStaticCompileTest.groovy   |  19 ----
 7 files changed, 187 insertions(+), 128 deletions(-)

diff --git 
a/src/main/java/org/codehaus/groovy/runtime/ScriptBytecodeAdapter.java 
b/src/main/java/org/codehaus/groovy/runtime/ScriptBytecodeAdapter.java
index 483e016524..308e793a85 100644
--- a/src/main/java/org/codehaus/groovy/runtime/ScriptBytecodeAdapter.java
+++ b/src/main/java/org/codehaus/groovy/runtime/ScriptBytecodeAdapter.java
@@ -47,6 +47,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
+import java.util.stream.BaseStream;
 
 /**
  * A static helper class to interface bytecode and runtime
@@ -920,17 +921,22 @@ public class ScriptBytecodeAdapter {
     //spread
     public static Object[] despreadList(final Object[] args, final Object[] 
spreads, final int[] positions) {
         List<Object> ret = new ArrayList<>();
-        int argsPos = 0;
-        int spreadPos = 0;
+        int argsPos = 0, spreadsPos = 0;
         for (int position : positions) {
-            for (; argsPos < position; argsPos++) {
+            for (; argsPos < position; ++argsPos) {
                 ret.add(args[argsPos]);
             }
-            Object value = spreads[spreadPos];
+            Object value = spreads[spreadsPos];
             if (value == null) {
                 ret.add(null);
             } else if (value instanceof List) {
                 ret.addAll((List<?>) value);
+            } else if (value instanceof Iterable) {
+                ((Iterable<?>) value).forEach(ret::add);
+            } else if (value instanceof Iterator) {
+                ((Iterator<?>) value).forEachRemaining(ret::add);
+            } else if (value instanceof BaseStream) {
+                ((BaseStream<?,?>) 
value).iterator().forEachRemaining(ret::add);
             } else if (value.getClass().isArray()) {
                 
ret.addAll(DefaultTypeTransformation.primitiveArrayToList(value));
             } else {
@@ -940,9 +946,9 @@ public class ScriptBytecodeAdapter {
                 }
                 throw new IllegalArgumentException(error);
             }
-            spreadPos++;
+            ++spreadsPos;
         }
-        for (; argsPos < args.length; argsPos++) {
+        for (; argsPos < args.length; ++argsPos) {
             ret.add(args[argsPos]);
         }
         return ret.toArray();
diff --git a/src/test/gls/invocation/MethodSelectionTest.groovy 
b/src/test/gls/invocation/MethodSelectionTest.groovy
index e347bbb2f8..9c0f3698fd 100644
--- a/src/test/gls/invocation/MethodSelectionTest.groovy
+++ b/src/test/gls/invocation/MethodSelectionTest.groovy
@@ -229,19 +229,6 @@ final class MethodSelectionTest extends 
gls.CompilableTestSupport {
         '''
     }
 
-    void testSpreadOperatorAndVarargs(){
-        assertScript '''
-            class SpreadBug {
-                def foo(String... args) {
-                    bar(*args)
-                }
-                def bar(String... args) {args.length}
-            }
-            def sb = new SpreadBug()
-            assert sb.foo("1","42")==2
-        '''
-    }
-
     // GROOVY-3977
     void testBDandBIToFloatAutoConversionInMethodSelection() {
         assertScript '''
diff --git a/src/test/groovy/GroovyMethodsTest.groovy 
b/src/test/groovy/GroovyMethodsTest.groovy
index d42aca5084..7a761e5d2b 100644
--- a/src/test/groovy/GroovyMethodsTest.groovy
+++ b/src/test/groovy/GroovyMethodsTest.groovy
@@ -19,16 +19,16 @@
 package groovy
 
 import groovy.test.GroovyTestCase
+import org.codehaus.groovy.util.StringUtil
 
 import java.awt.Dimension
 import java.nio.CharBuffer
 import java.util.concurrent.LinkedBlockingQueue
-import org.codehaus.groovy.util.StringUtil
 
 /**
  * Tests various GDK methods
  */
-class GroovyMethodsTest extends GroovyTestCase {
+final class GroovyMethodsTest extends GroovyTestCase {
 
     void testAbs() {
         def absoluteNumberOne = 1
@@ -2357,7 +2357,7 @@ class WackyHashCode {
 }
 
 class Things implements Iterable<String> {
-    Iterator iterator() {
+    Iterator<String> iterator() {
         ["a", "B", "c"].iterator()
     }
 }
diff --git a/src/test/groovy/SpreadArgTest.groovy 
b/src/test/groovy/SpreadArgTest.groovy
new file mode 100644
index 0000000000..c40e0fc645
--- /dev/null
+++ b/src/test/groovy/SpreadArgTest.groovy
@@ -0,0 +1,117 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package groovy
+
+import org.junit.Test
+
+import static groovy.test.GroovyAssert.assertScript
+
+/**
+ * Tests for the spread arg(s) operator "m(*x)".
+ */
+final class SpreadArgTest {
+
+    // GROOVY-9515
+    @Test
+    void testSpreadList() {
+        assertScript '''
+            int f(int x, int y) { x + y }
+            int f(int x) { x }
+            int g(x) { f(*x) }
+
+            assert g([1]) == 1
+            assert g([1, 2]) == 3
+        '''
+    }
+
+    @Test
+    void testSpreadArray() {
+        assertScript '''
+            int f(int x, int y, int z) {
+                x + y + z
+            }
+
+            Number[] nums = [1, 2, 39]
+            assert f(*nums) == 42
+        '''
+    }
+
+    // GROOVY-11186
+    @Test
+    void testSpreadOther() {
+        assertScript '''
+            int f(int x, int y, int z) {
+                x + y + z
+            }
+
+            Set<Number> nums = [1, 2, 39]
+            assert f(*nums) == 42
+        '''
+    }
+
+    // GROOVY-11186
+    @Test
+    void testSpreadStream() {
+        assertScript '''
+            int f(int x, int y, int z) {
+                x + y + z
+            }
+
+            def nums = java.util.stream.IntStream.of(1, 2, 39)
+            assert f(*nums) == 42
+        '''
+    }
+
+    // GROOVY-5647
+    @Test
+    void testSpreadSkipSTC() {
+        assertScript '''
+            import groovy.transform.CompileStatic
+            import static groovy.transform.TypeCheckingMode.SKIP
+
+            @CompileStatic
+            class C {
+                @CompileStatic(SKIP)
+                def foo(fun, args) {
+                    new Runnable() { // create an anonymous class which should 
*not* be visited
+                        void run() {
+                            fun(*args) // spread operator is disallowed with 
STC/SC, but SKIP should prevent from an error
+                        }
+                    }
+                }
+            }
+
+            new C()
+        '''
+    }
+
+    @Test
+    void testSpreadVarargs() {
+        assertScript '''
+            int f(String... strings) {
+                g(*strings)
+            }
+            int g(String... strings) {
+                strings.length
+            }
+
+            assert f("1","2") == 2
+        '''
+    }
+}
diff --git a/src/test/groovy/SpreadDotTest.groovy 
b/src/test/groovy/SpreadDotTest.groovy
index 75747523ee..164cb34b24 100644
--- a/src/test/groovy/SpreadDotTest.groovy
+++ b/src/test/groovy/SpreadDotTest.groovy
@@ -18,17 +18,21 @@
  */
 package groovy
 
-import groovy.test.GroovyTestCase
+import org.junit.Test
+
+import static org.junit.Assert.assertEquals
 
 /**
- * Test for the spread dot operator "*.".
+ * Tests for the spread dot operator "*.".
  *
  * For an example,
  *          list*.property
  * means
  *          list.collect { it?.property }
  */
-class SpreadDotTest extends GroovyTestCase {
+final class SpreadDotTest {
+
+    @Test
     void testSpreadDot() {
         def m1 = ["a": 1, "b": 2]
         def m2 = ["a": 11, "b": 22]
@@ -59,6 +63,7 @@ class SpreadDotTest extends GroovyTestCase {
         assert x == [m1, m2, m3, null, d, y]
     }
 
+    @Test
     void testSpreadDot2() {
         def a = new SpreadDotDemo()
         def b = new SpreadDotDemo2()
@@ -68,6 +73,7 @@ class SpreadDotTest extends GroovyTestCase {
         assert [a, b]*.fnB() == [a.fnB(), b.fnB()]
     }
 
+    @Test
     void testSpreadDotArrays() {
         def a = new SpreadDotDemo()
         def b = new SpreadDotDemo2()
@@ -86,16 +92,18 @@ class SpreadDotTest extends GroovyTestCase {
         assert pets*.length() == nums
     }
 
-    void testSpreadDotOnArrays2() {
+    @Test
+    void testSpreadDotArrays2() {
         def books = [Book1, Book2, Book3] as Object[]
 
-        books*.metaClass*.foo = { "Hello, ${delegate.class.name}" }
+        books*.metaClass*.foo = { "Hello, 
${delegate.class.simpleName}".toString() }
 
-        assertEquals "Hello, groovy.Book1", new Book1().foo()
-        assertEquals "Hello, groovy.Book2", new Book2().foo()
-        assertEquals "Hello, groovy.Book3", new Book3().foo()
+        assertEquals("Hello, Book1", new Book1().foo())
+        assertEquals("Hello, Book2", new Book2().foo())
+        assertEquals("Hello, Book3", new Book3().foo())
     }
 
+    @Test
     void testSpreadDotAdvanced() {
         assertEquals([3, 3], ['cat', 'dog']*.size())
         assertEquals([3, 3], (['cat', 'dog'] as Vector)*.size())
@@ -108,6 +116,7 @@ class SpreadDotTest extends GroovyTestCase {
         assertEquals(['Large'], new Shirt()*.size())
     }
 
+    @Test
     void testSpreadDotMap() {
         def map = [A: "one", B: "two", C: "three"]
         assert map.collect { child -> child.value.size() } == [3, 3, 5]
@@ -115,6 +124,7 @@ class SpreadDotTest extends GroovyTestCase {
         assert map*.getKey() == ['A', 'B', 'C']
     }
 
+    @Test
     void testSpreadDotAttribute() {
         def s = new Singlet()
         assert s.size == 1
@@ -124,7 +134,8 @@ class SpreadDotTest extends GroovyTestCase {
         assert wardrobe*.@size == [12, 12]
     }
 
-    void testNewLine() {
+    @Test
+    void testSpreadDotMultiLine() {
         def x = [a: 1, b: 2]
         def y = x
                 *.value
@@ -140,53 +151,53 @@ class SpreadDotTest extends GroovyTestCase {
                 *.@size
         assert y == [12, 12]
     }
-}
-
-class SpreadDotDemo {
-    java.util.Date getA() {
-        return new Date()
-    }
 
-    String fnB() {
-        return "bb"
-    }
+    
//--------------------------------------------------------------------------
 
-    String fnB(String m) {
-        return "BB$m"
-    }
-}
+    static class SpreadDotDemo {
+        Date getA() {
+            return new Date()
+        }
 
-class SpreadDotDemo2 {
-    String getAttribute(String key) {
-        return "Attribute $key"
-    }
+        String fnB() {
+            return "bb"
+        }
 
-    String get(String key) {
-        return getAttribute("Get $key")
+        String fnB(String m) {
+            return "BB$m"
+        }
     }
 
-    String fnB() {
-        return "cc"
-    }
+    static class SpreadDotDemo2 {
+        String getAttribute(String key) {
+            return "Attribute $key"
+        }
 
-    String fnB(String m) {
-        return "CC$m"
-    }
-}
+        String get(String key) {
+            return getAttribute("Get $key")
+        }
 
+        String fnB() {
+            return "cc"
+        }
 
-class Book1 {}
+        String fnB(String m) {
+            return "CC$m"
+        }
+    }
 
-class Book2 {}
+    static class Book1 {}
 
-class Book3 {}
+    static class Book2 {}
 
-class Shirt {
-    def size() { 'Large' }
-}
+    static class Book3 {}
 
-class Singlet {
-    private size = 12
+    static class Shirt {
+        def size() { 'Large' }
+    }
 
-    def getSize() { 1 }
+    static class Singlet {
+        private size = 12
+        def getSize() {1}
+    }
 }
diff --git a/src/test/groovy/bugs/Groovy9515.groovy 
b/src/test/groovy/bugs/Groovy9515.groovy
deleted file mode 100644
index d24da084a6..0000000000
--- a/src/test/groovy/bugs/Groovy9515.groovy
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package groovy.bugs
-
-import groovy.transform.CompileStatic
-import org.codehaus.groovy.control.CompilerConfiguration
-import org.junit.Test
-
-@CompileStatic
-final class Groovy9515 {
-
-    @Test
-    void testSpreadArgsIndy() {
-        def config = new CompilerConfiguration()
-        config.optimizationOptions.indy = true
-        new GroovyShell(config).evaluate '''
-def x(int a) {a}
-def x(int a, int b) {a + b}
-def y(p) {
-    x(*p)
-}
-
-assert 1 == y([1])
-assert 3 == y([1, 2])
-'''
-    }
-}
diff --git 
a/src/test/org/codehaus/groovy/classgen/asm/sc/BugsStaticCompileTest.groovy 
b/src/test/org/codehaus/groovy/classgen/asm/sc/BugsStaticCompileTest.groovy
index e8ca9036f5..4e99b8c489 100644
--- a/src/test/org/codehaus/groovy/classgen/asm/sc/BugsStaticCompileTest.groovy
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/BugsStaticCompileTest.groovy
@@ -415,25 +415,6 @@ final class BugsStaticCompileTest extends BugsSTCTest 
implements StaticCompilati
         '''
     }
 
-    void testShouldSkipSpreadOperator() {
-        new GroovyShell().evaluate '''import groovy.transform.CompileStatic
-            import static groovy.transform.TypeCheckingMode.SKIP
-
-            @CompileStatic // top level must be @CS
-            class Foo {
-                @CompileStatic(SKIP)
-                static void foo(fun, args) {
-                    new Runnable() { // create an anonymous class which should 
*not* be visited
-                        void run() {
-                            fun(*args) // spread operator is disallowed with 
STC/SC, but SKIP should prevent from an error
-                        }
-                    }
-                }
-            }
-            new Foo()
-        '''
-    }
-
     // GROOVY-5672
     void testTypeCheckedPlusCompileStatic() {
         new GroovyShell().evaluate '''import groovy.transform.*

Reply via email to