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/07/28 21:55:37 UTC

[groovy] branch master updated: GROOVY-8487: SC: for-in loop over iterator

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 09b5c7c3e4 GROOVY-8487: SC: for-in loop over iterator
09b5c7c3e4 is described below

commit 09b5c7c3e44b6d17cb4f8d2a5e74244e34f19646
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Thu Jul 28 16:35:49 2022 -0500

    GROOVY-8487: SC: for-in loop over iterator
---
 .../asm/sc/StaticTypesStatementWriter.java         | 36 ++++++++++++----------
 .../groovy/runtime/DefaultGroovyMethods.java       |  3 +-
 src/test/groovy/transform/stc/LoopsSTCTest.groovy  | 22 +++++++++++++
 .../groovy/transform/stc/MethodCallsSTCTest.groovy | 11 -------
 4 files changed, 44 insertions(+), 28 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesStatementWriter.java b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesStatementWriter.java
index 0e7db374a1..b05c90dffc 100644
--- a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesStatementWriter.java
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesStatementWriter.java
@@ -219,23 +219,27 @@ public class StaticTypesStatementWriter extends StatementWriter {
     }
 
     private void writeIteratorBasedForEachLoop(final ForStatement loop, final Expression collectionExpression, final ClassNode collectionType) {
-        // GROOVY-10476: BaseStream provides an iterator() but does not implement Iterable
-        MethodNode iterator = collectionType.getMethod("iterator", Parameter.EMPTY_ARRAY);
-        if (iterator == null) {
-            iterator = GeneralUtils.getInterfacesAndSuperInterfaces(collectionType).stream()
-                    .map(in -> in.getMethod("iterator", Parameter.EMPTY_ARRAY))
-                    .filter(Objects::nonNull).findFirst().orElse(null);
-        }
-        if (iterator != null && GeneralUtils.isOrImplements(iterator.getReturnType(), ClassHelper.Iterator_TYPE)) {
-            MethodCallExpression call = GeneralUtils.callX(collectionExpression, "iterator");
-            call.setImplicitThis(false);
-            call.setMethodTarget(iterator);
-            call.setSafe(true);//GROOVY-8643
-            call.visit(controller.getAcg());
+        if (GeneralUtils.isOrImplements(collectionType, ClassHelper.Iterator_TYPE)) {
+            collectionExpression.visit(controller.getAcg()); // GROOVY-8487: iterator supplied
         } else {
-            collectionExpression.visit(controller.getAcg());
-            controller.getMethodVisitor().visitMethodInsn(INVOKESTATIC, "org/codehaus/groovy/runtime/DefaultGroovyMethods", "iterator", "(Ljava/lang/Object;)Ljava/util/Iterator;", false);
-            controller.getOperandStack().replace(ClassHelper.Iterator_TYPE);
+            // GROOVY-10476: BaseStream provides an iterator() but does not implement Iterable
+            MethodNode iterator = collectionType.getMethod("iterator", Parameter.EMPTY_ARRAY);
+            if (iterator == null) {
+                iterator = GeneralUtils.getInterfacesAndSuperInterfaces(collectionType).stream()
+                        .map(in -> in.getMethod("iterator", Parameter.EMPTY_ARRAY))
+                        .filter(Objects::nonNull).findFirst().orElse(null);
+            }
+            if (iterator != null && GeneralUtils.isOrImplements(iterator.getReturnType(), ClassHelper.Iterator_TYPE)) {
+                MethodCallExpression call = GeneralUtils.callX(collectionExpression, "iterator");
+                call.setImplicitThis(false);
+                call.setMethodTarget(iterator);
+                call.setSafe(true);//GROOVY-8643
+                call.visit(controller.getAcg());
+            } else {
+                collectionExpression.visit(controller.getAcg());
+                controller.getMethodVisitor().visitMethodInsn(INVOKESTATIC, "org/codehaus/groovy/runtime/DefaultGroovyMethods", "iterator", "(Ljava/lang/Object;)Ljava/util/Iterator;", false);
+                controller.getOperandStack().replace(ClassHelper.Iterator_TYPE);
+            }
         }
         writeForInLoopControlAndBlock(loop);
     }
diff --git a/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java b/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
index 0133358fa3..f1b4bfb3de 100644
--- a/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
+++ b/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
@@ -18115,7 +18115,8 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      * @see org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation#asCollection(java.lang.Object)
      * @since 1.0
      */
-    public static Iterator iterator(Object o) {
+    public static Iterator iterator(final Object o) {
+        if (o instanceof Iterator) return (Iterator)o;
         return DefaultTypeTransformation.asCollection(o).iterator();
     }
 
diff --git a/src/test/groovy/transform/stc/LoopsSTCTest.groovy b/src/test/groovy/transform/stc/LoopsSTCTest.groovy
index 792466212c..ceab418ec3 100644
--- a/src/test/groovy/transform/stc/LoopsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/LoopsSTCTest.groovy
@@ -213,6 +213,17 @@ class LoopsSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
+    // GROOVY-10476
+    void testForInLoopOnStream() {
+        assertScript '''
+            def list = []
+            for (item in ['a','b','c'].stream()) {
+                list.add(item.toUpperCase())
+            }
+            assert list == ['A','B','C']
+        '''
+    }
+
     // GROOVY-8882
     void testForInLoopOnString() {
         assertScript '''
@@ -225,6 +236,17 @@ class LoopsSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
+    // GROOVY-8487
+    void testForInLoopOnIterator() {
+        assertScript '''
+            def list = []
+            for (item in ['a','b','c'].iterator()) {
+                list.add(item)
+            }
+            assert list.join('') == 'abc'
+        '''
+    }
+
     // GROOVY-6123
     void testForInLoopOnEnumeration() {
         assertScript '''
diff --git a/src/test/groovy/transform/stc/MethodCallsSTCTest.groovy b/src/test/groovy/transform/stc/MethodCallsSTCTest.groovy
index 78219b7644..dde7baa599 100644
--- a/src/test/groovy/transform/stc/MethodCallsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/MethodCallsSTCTest.groovy
@@ -1268,17 +1268,6 @@ class MethodCallsSTCTest extends StaticTypeCheckingTestCase {
         'Cannot call closure that accepts [java.lang.String, java.lang.String, java.lang.String] with '
     }
 
-    // GROOVY-10476
-    void testForInLoop() {
-        assertScript '''
-            def list = []
-            for (item in ['a','b','c'].stream()) {
-                list.add(item.toUpperCase())
-            }
-            assert list == ['A', 'B', 'C']
-        '''
-    }
-
     void testBoxingShouldCostMore() {
         assertScript '''
             int foo(int x) { 1 }