Skip to content

Commit

Permalink
Merge pull request #863 from Thrameos/vararg
Browse files Browse the repository at this point in the history
Fixed variadic method resolution
  • Loading branch information
marscher authored Oct 19, 2020
2 parents 2ebece0 + 9363817 commit 0608847
Show file tree
Hide file tree
Showing 4 changed files with 138 additions and 5 deletions.
3 changes: 3 additions & 0 deletions doc/CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ This changelog *only* contains changes from the *first* pypi release (0.5.4.3) o

Latest Changes:
- **1.0.3_dev0 - unreleased**

- Correct bug resulting in reporting ambiguous overloads when resolving
methods with variadic arguments.

- Ctrl+C behavior is switchable with interrupt flag to startJVM.
If True, process will halt on Ctrl-C. If False, the process
Expand Down
94 changes: 89 additions & 5 deletions native/java/org/jpype/manager/MethodResolution.java
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ static Class[] of(Class... l)
}
static HashMap<Class, Class[]> CONVERSION = new HashMap<>();


{
CONVERSION.put(Byte.TYPE,
of(Byte.TYPE, Byte.class, Short.TYPE, Short.class,
Expand Down Expand Up @@ -172,15 +172,99 @@ public static boolean isMoreSpecificThan(Executable method1, Executable method2)
List<Class<?>> param1 = new ArrayList<>(Arrays.asList(method1.getParameterTypes()));
List<Class<?>> param2 = new ArrayList<>(Arrays.asList(method2.getParameterTypes()));

// This line prevents ambiguity resolution both static and method forms.
// if (Modifier.isStatic(method1.getModifiers())
// != Modifier.isStatic(method2.getModifiers()))
// return false;
if (!Modifier.isStatic(method1.getModifiers()))
param1.add(0, method1.getDeclaringClass());
if (!Modifier.isStatic(method2.getModifiers()))
param2.add(0, method2.getDeclaringClass());

// Special handling is needed for varargs as it may chop or expand.
// we have 4 cases for a varargs methods
// foo(Arg0, Arg1...) as
// foo(Arg0)
// foo(Arg0, Arg1)
// foo(Arg0, Arg1[])
// foo(Arg0, Arg1, Arg1+)
if (method1.isVarArgs() && method2.isVarArgs())
{
// Punt on this as there are too many different cases
return isMoreSpecificThan(param1, param2);
}

if (method1.isVarArgs())
{
int n1 = param1.size();
int n2 = param2.size();

// Last element is an array
Class<?> cls = param1.get(n1 - 1);
Class<?> cls2 = cls.getComponentType();

// Less arguments, chop the list
if (n1 - 1 == n2)
return isMoreSpecificThan(param1.subList(0, n2), param2);

// Same arguments
if (n1 == n2)
{
List<Class<?>> q = new ArrayList<>(param1);
q.set(n1 - 1, cls2);

// Check both ways
return isMoreSpecificThan(param1, param2) || isMoreSpecificThan(q, param2);
}

// More arguments
if (n1 < n2)
{
// Grow the list
List<Class<?>> q = new ArrayList<>(param1);
q.set(n1 - 1, cls2);
for (int i = n1; i < n2; ++i)
q.add(cls2);
return isMoreSpecificThan(q, param2);
}
}

if (method2.isVarArgs())
{
int n1 = param1.size();
int n2 = param2.size();

// Last element is an array
Class<?> cls = param2.get(n2 - 1);
Class<?> cls2 = cls.getComponentType();

// Less arguments, chop the list
if (n2 - 1 == n1)
return isMoreSpecificThan(param1, param2.subList(0, n2));

// Same arguments
if (n1 == n2)
{
List<Class<?>> q = new ArrayList<>(param2);
q.set(n2 - 1, cls2);

// Compare both ways
return isMoreSpecificThan(param1, param2) || isMoreSpecificThan(param1, q);
}

// More arguments
if (n2 < n1)
{
// Grow the list
List<Class<?>> q = new ArrayList<>(param2);
q.set(n2 - 1, cls2);
for (int i = n2; i < n1; ++i)
q.add(cls2);
return isMoreSpecificThan(param1, q);
}
}

return isMoreSpecificThan(param1, param2);
}

public static boolean isMoreSpecificThan(List<Class<?>> param1, List<Class<?>> param2)
{
// FIXME need to consider resolving mixing of static and non-static
// Methods here.
if (param1.size() != param2.size())
Expand Down
33 changes: 33 additions & 0 deletions test/harness/jpype/varargs/VarArgs.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
**************************************************************************** */
package jpype.varargs;

import java.util.Map;

class VarArgs
{

Expand Down Expand Up @@ -63,4 +65,35 @@ public String[] method(String s, String... rest)
{
return rest;
}

public int conflict1(Object... j)
{
return 1;
}

public int conflict1(Map j)
{
return 2;
}

public int conflict2(Object... j)
{
return 1;
}

public int conflict2(Map j, Map k)
{
return 2;
}


public int conflict3(char... j)
{
return 1;
}

public int conflict3(String j)
{
return 2;
}
}
13 changes: 13 additions & 0 deletions test/jpypetest/test_varargs.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,19 @@ def setUp(self):
self.String = jpype.JClass('java.lang.String')
self.StringA = jpype.JArray(self.String)

def testConflict(self):
m = jpype.java.util.LinkedHashMap({"a": 1, "b": 2, "c": 3})
test = self.VarArgs()
self.assertEqual(test.conflict2([1, 2, 3]), 1)
self.assertEqual(test.conflict2(m, m), 2)
self.assertEqual(test.conflict3(['h', 'e']), 1)
self.assertEqual(test.conflict3('h'), 2)
self.assertEqual(test.conflict3('hello'), 2)
self.assertEqual(test.conflict1(1), 1)
self.assertEqual(test.conflict1([1, 2, 3]), 1)
self.assertEqual(test.conflict1({"a": 1, "b": 2, "c": 3}), 2)
self.assertEqual(test.conflict1(m), 2)

def testVarArgsCtor(self):
va0 = self.VarArgs('1')
va1 = self.VarArgs('1', 'a')
Expand Down

0 comments on commit 0608847

Please sign in to comment.