[ 
https://issues.apache.org/jira/browse/GROOVY-12165?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18096138#comment-18096138
 ] 

ASF GitHub Bot commented on GROOVY-12165:
-----------------------------------------

Copilot commented on code in PR #2712:
URL: https://github.com/apache/groovy/pull/2712#discussion_r3578208062


##########
src/test/groovy/bugs/Groovy12165.groovy:
##########
@@ -0,0 +1,151 @@
+/*
+ *  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 bugs
+
+import org.junit.jupiter.api.Test
+
+import static groovy.test.GroovyAssert.assertScript
+
+/**
+ * {@code Closure.call}'s cached fast path covered only zero- and one-argument
+ * overrides (GROOVY-11911, GROOVY-12164), so every multi-argument closure call
+ * from Java — all {@code Map} iteration, {@code eachWithIndex}, {@code inject}
+ * — took full metaclass dispatch. GROOVY-12165 generalises the cache to an
+ * arity-indexed table (0..4) with per-argument instance-of guards: at each
+ * arity an all-{@code Object} override wins outright, otherwise the single
+ * unambiguous typed override dispatches when every argument is already an
+ * instance of its declared type, and anything else (coercion, null, ambiguity)
+ * falls through to the metaclass exactly as before. These tests pin both sides
+ * of the guards at the new arities; iteration goes through DGM, whose Java
+ * code invokes {@code closure.call(...)}, the path the cache serves.
+ */
+final class Groovy12165 {
+
+    @Test
+    void testMapIterationUntyped() {
+        assertScript '''
+            def m = [a: 1, b: 2, c: 3]
+            int sum = 0
+            def keys = []
+            m.each { k, v -> keys << k; sum += (int) v }
+            assert keys == ['a', 'b', 'c']
+            assert sum == 6
+            assert m.collect { k, v -> "$k$v".toString() } == ['a1', 'b2', 
'c3']
+        '''
+    }
+
+    @Test
+    void testMapIterationTyped() {
+        assertScript '''
+            def m = [a: 1, b: 2]
+            int sum = 0
+            m.each { String k, Integer v -> sum += v }
+            assert sum == 3
+            assert m.any { String k, Integer v -> v == 2 }
+            assert m.every { String k, Integer v -> v > 0 }
+        '''
+    }
+
+    @Test
+    void testEachWithIndexAndInject() {
+        assertScript '''
+            def seen = []
+            ['a', 'b'].eachWithIndex { x, i -> seen << "$i:$x".toString() }
+            assert seen == ['0:a', '1:b']
+            assert [1, 2, 3, 4].inject(0) { a, x -> (int) a + (int) x } == 10
+            assert [1, 2, 3].inject(1) { Integer a, Integer x -> a * x } == 6
+        '''
+    }
+
+    @Test
+    void testThreeArgumentClosure() {
+        assertScript '''
+            // Map#inject drives a three-parameter closure with (acc, key, 
value) from Java
+            assert [a: 1, b: 2, c: 3].inject(0) { acc, k, v -> (int) acc + 
(int) v } == 6
+            assert [a: 1, b: 2].inject(0) { Integer acc, String k, Integer v 
-> acc + v } == 3
+        '''
+    }
+
+    @Test
+    void testTypedGuardFallsThroughToCoercion() {
+        assertScript '''
+            // GString key coerces to the String parameter on the metaclass 
path
+            def name = 'a'
+            def m = [("k${name}".toString()): 1]

Review Comment:
   This test intends to exercise the metaclass/coercion path with a GString map 
key, but `("k${name}".toString())` materializes a `String` key up front, so the 
fast-path guard may still pass and the coercion behavior is not actually 
covered. Keep the key as a GString to ensure the guard fails and the call falls 
through as described in the comment.





> 2-arg typed/untyped map iteration, guard fall-through at arity 2, ambiguous 
> same-arity overloads, static decline
> ----------------------------------------------------------------------------------------------------------------
>
>                 Key: GROOVY-12165
>                 URL: https://issues.apache.org/jira/browse/GROOVY-12165
>             Project: Groovy
>          Issue Type: Improvement
>            Reporter: Paul King
>            Assignee: Paul King
>            Priority: Major
>




--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to