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/08/23 17:11:28 UTC

[groovy] branch GROOVY_2_5_X updated: GROOVY-8737: STC: no varargs distance for exact match of variadic method

This is an automated email from the ASF dual-hosted git repository.

emilles pushed a commit to branch GROOVY_2_5_X
in repository https://gitbox.apache.org/repos/asf/groovy.git


The following commit(s) were added to refs/heads/GROOVY_2_5_X by this push:
     new 362ff57b86 GROOVY-8737: STC: no varargs distance for exact match of variadic method
362ff57b86 is described below

commit 362ff57b8630dd43f9a381a96b794e2b98ddbc94
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Tue Aug 23 10:57:45 2022 -0500

    GROOVY-8737: STC: no varargs distance for exact match of variadic method
---
 .../transform/stc/StaticTypeCheckingSupport.java   |  33 ++--
 .../groovy/transform/stc/MethodCallsSTCTest.groovy | 167 ++++++++++++++-------
 2 files changed, 129 insertions(+), 71 deletions(-)

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 df761f4c21..f1428f3aea 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
@@ -1144,34 +1144,35 @@ public abstract class StaticTypeCheckingSupport {
         return bestChoices;
     }
 
-    private static int measureParametersAndArgumentsDistance(Parameter[] params, ClassNode[] args) {
+    private static int measureParametersAndArgumentsDistance(final Parameter[] parameters, final ClassNode[] argumentTypes) {
         int dist = -1;
-        if (params.length == args.length) {
-            int allPMatch = allParametersAndArgumentsMatch(params, args);
-            int firstParamDist = firstParametersAndArgumentsMatch(params, args);
-            int lastArgMatch = isVargs(params) && firstParamDist >= 0 ? lastArgMatchesVarg(params, args) : -1;
-            if (lastArgMatch >= 0) {
-                lastArgMatch += getVarargsDistance(params);
+        if (parameters.length == argumentTypes.length) {
+            dist = allParametersAndArgumentsMatch(parameters, argumentTypes);
+            if (isVargs(parameters) && firstParametersAndArgumentsMatch(parameters, argumentTypes) >= 0) {
+                int endDist = lastArgMatchesVarg(parameters, argumentTypes);
+                if (endDist >= 0) {
+                    endDist += getVarargsDistance(parameters);
+                    dist = (dist < 0 ? endDist : Math.min(dist, endDist)); // GROOVY-8737
+                }
             }
-            dist = allPMatch >= 0 ? Math.max(allPMatch, lastArgMatch) : lastArgMatch;
-        } else if (isVargs(params)) {
-            dist = firstParametersAndArgumentsMatch(params, args);
+        } else if (isVargs(parameters)) {
+            dist = firstParametersAndArgumentsMatch(parameters, argumentTypes);
             if (dist >= 0) {
                 // varargs methods must not be preferred to methods without varargs
                 // for example :
                 // int sum(int x) should be preferred to int sum(int x, int... y)
-                dist += getVarargsDistance(params);
+                dist += getVarargsDistance(parameters);
                 // there are three case for vargs
                 // (1) varg part is left out (there's one less argument than there are parameters)
                 // (2) last argument is put in the vargs array
                 //     that case is handled above already when params and args have the same length
-                if (params.length < args.length) {
+                if (parameters.length < argumentTypes.length) {
                     // (3) there is more than one argument for the vargs array
-                    int excessArgumentsDistance = excessArgumentsMatchesVargsParameter(params, args);
-                    if (excessArgumentsDistance < 0) {
-                        dist = -1;
-                    } else {
+                    int excessArgumentsDistance = excessArgumentsMatchesVargsParameter(parameters, argumentTypes);
+                    if (excessArgumentsDistance >= 0) {
                         dist += excessArgumentsDistance;
+                    } else {
+                        dist = -1;
                     }
                 }
             }
diff --git a/src/test/groovy/transform/stc/MethodCallsSTCTest.groovy b/src/test/groovy/transform/stc/MethodCallsSTCTest.groovy
index 3d8324aae7..735fac4908 100644
--- a/src/test/groovy/transform/stc/MethodCallsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/MethodCallsSTCTest.groovy
@@ -962,7 +962,7 @@ class MethodCallsSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
-    void testVargsSelection() {
+    void testVargsSelection1() {
         assertScript '''
             int foo(int x, Object... args) { 1 }
             int foo(Object... args) { 2 }
@@ -972,6 +972,116 @@ class MethodCallsSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
+    void testVargsSelection2() {
+        assertScript '''
+            int sum(int x) { 1 }
+            int sum(int... args) {
+                0
+            }
+            assert sum(1) == 1
+        '''
+    }
+
+    void testVargsSelection3() {
+        assertScript '''
+            int sum(int x) { 1 }
+            int sum(int y, int... args) {
+                0
+            }
+            assert sum(1) == 1
+        '''
+    }
+
+    // GROOVY-6147
+    void testVargsSelection4() {
+        assertScript '''
+            int select(Object a, String s) { 1 }
+            int select(Object a, String s, Object[] args) { 2 }
+            def o = new Date()
+            def s = 'String'
+            @ASTTest(phase=INSTRUCTION_SELECTION,value={
+                def method = node.rightExpression.getNodeMetaData(DIRECT_METHOD_CALL_TARGET)
+                assert method.name == 'select'
+                assert method.parameters.length==2
+            })
+            def result = select(o,s)
+            assert result == 1
+        '''
+    }
+
+    // GROOVY-6195
+    void testVargsSelection5() {
+        assertScript '''
+            def list = ['a', 'b', 'c']
+            Object[] arr = list.toArray()
+            println arr
+        '''
+    }
+
+    // GROOVY-6235
+    void testVargsSelection6() {
+        assertScript '''import org.codehaus.groovy.classgen.asm.sc.support.Groovy6235SupportSub as Support
+            def b = new Support()
+            assert b.overload() == 1
+            assert b.overload('a') == 1
+            assert b.overload('a','b') == 2
+        '''
+    }
+
+    // GROOVY-6646
+    void testVargsSelection7() {
+        assertScript '''
+            def foo(Class... cs) { "Classes" }
+            def foo(String... ss) { "Strings" }
+
+            assert foo(List, Map) == "Classes"
+            assert foo("2","1") == "Strings"
+        '''
+        assertScript '''
+            def foo(Class<?>... cs) { "Classes" }
+            def foo(String... ss) { "Strings" }
+
+            assert foo(List, Map) == "Classes"
+            assert foo("2","1") == "Strings"
+        '''
+    }
+
+    // GROOVY-8737
+    void testVargsSelection8() {
+        String methods = '''
+            String m(String key, Object[] args) {
+                "key=$key, args=$args"
+            }
+            String m(String key, Object[] args, Object[] parts) {
+                "key=$key, args=$args, parts=$parts"
+            }
+            String m(String key, Object[] args, String[] names) {
+                "key=$key, args=$args, names=$names"
+            }
+        '''
+        assertScript methods + '''
+            String result = m( 'hello', ['world'] as Object[] ) // exact match for m(String,Object[])
+            assert result == 'key=hello, args=[world]'
+        '''
+        assertScript methods + '''
+            String result = m( 'hello', ['world'] as String[] )
+            assert result == 'key=hello, args=[world]'
+        '''
+        assertScript methods + '''
+            String result = m( "${'hello'}", 'world' )
+            assert result == 'key=hello, args=[world]'
+        '''
+        assertScript methods + '''
+            String result = m( 'hello', 'world' )
+            assert result == 'key=hello, args=[world]'
+        '''
+
+        assertScript methods + '''
+            String result = m( 'hello', ['there'] as String[], 'Steve' )
+            assert result == 'key=hello, args=[there], names=[Steve]'
+        '''
+    }
+
     // GROOVY-5702
     void testShouldFindInterfaceMethod() {
         assertScript '''
@@ -1182,41 +1292,6 @@ class MethodCallsSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
-    // GROOVY-6147
-    void testVargsCallWithOverloadedMethod() {
-        assertScript '''
-            int select(Object a, String s) { 1 }
-            int select(Object a, String s, Object[] args) { 2 }
-            def o = new Date()
-            def s = 'String'
-            @ASTTest(phase=INSTRUCTION_SELECTION,value={
-                def method = node.rightExpression.getNodeMetaData(DIRECT_METHOD_CALL_TARGET)
-                assert method.name == 'select'
-                assert method.parameters.length==2
-            })
-            def result = select(o,s)
-            assert result == 1
-        '''
-    }
-
-    // GROOVY-6195
-    void testShouldNotThrowAmbiguousVargs() {
-        assertScript '''
-            def list = ['a', 'b', 'c']
-            Object[] arr = list.toArray()
-            println arr
-        '''
-    }
-
-    void testOverloadedMethodWithVargs() {
-        assertScript '''import org.codehaus.groovy.classgen.asm.sc.support.Groovy6235SupportSub as Support
-            def b = new Support()
-            assert b.overload() == 1
-            assert b.overload('a') == 1
-            assert b.overload('a','b') == 2
-        '''
-    }
-
     // GROOVY-10720
     void testOverloadedMethodWithArray() {
         assertScript '''
@@ -1274,25 +1349,7 @@ class MethodCallsSTCTest extends StaticTypeCheckingTestCase {
         ''', 'Cannot find matching method java.lang.String#doSomething()'
     }
 
-    // GROOVY-6646
-    void testNPlusVargsCallInOverloadSituation() {
-        assertScript '''
-            def foo(Class... cs) { "Classes" }
-            def foo(String... ss) { "Strings" }
-
-            assert foo(List, Map) == "Classes"
-            assert foo("2","1") == "Strings"
-        '''
-        assertScript '''
-            def foo(Class<?>... cs) { "Classes" }
-            def foo(String... ss) { "Strings" }
-
-            assert foo(List, Map) == "Classes"
-            assert foo("2","1") == "Strings"
-        '''
-    }
-
-    //GROOVY-6776
+    // GROOVY-6776
     void testPrimtiveParameterAndNullArgument() {
         shouldFailWithMessages '''
             def foo(int i){}