Skip to content

Ensure that param-array matching works correctly #1304

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Dec 10, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/runtime/methodbinder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -512,7 +512,7 @@ static object[] TryConvertArguments(ParameterInfo[] pi, bool paramsArray,
{
if(arrayStart == paramIndex)
{
op = HandleParamsArray(args, arrayStart, pyArgCount, out isNewReference);
op = HandleParamsArray(args, arrayStart, pyArgCount, out isNewReference);
}
else
{
Expand Down Expand Up @@ -652,7 +652,7 @@ static bool MatchesArgumentCount(int positionalArgumentCount, ParameterInfo[] pa
{
match = true;
}
else if (positionalArgumentCount < parameters.Length)
else if (positionalArgumentCount < parameters.Length && (!paramsArray || positionalArgumentCount == parameters.Length - 1))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe it would be useful to comment explicitly on what kind of cases would fall into this condition, or simplify the branching statements somehow (refactor the default arg logic in a separate method)? Just by reading this I'm guessing that this should take care of only the following 2 cases?

  1. when it's not a params array but there are some default values we need to fill in
  2. when it's a params array and exactly one parameter is missing

Maybe there are more?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nevermind, actually I get it now! I also added an extra comment and renamed the variables for readability and consistency with the others parts of methodbinder in my PR: https://github.com/pythonnet/pythonnet/pull/1324/files#diff-237dc718ad5424f5476d2ebbbc4e5164c95901bd2a4c2daaf8ca6fc9f9d3a5fbR703-R704

{
// every parameter past 'positionalArgumentCount' must have either
// a corresponding keyword argument or a default parameter
Expand All @@ -677,7 +677,7 @@ static bool MatchesArgumentCount(int positionalArgumentCount, ParameterInfo[] pa
defaultArgList.Add(parameters[v].GetDefaultValue());
defaultsNeeded++;
}
else if(!paramsArray)
else if (!paramsArray)
{
match = false;
}
Expand Down
18 changes: 18 additions & 0 deletions src/testing/constructortests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,22 @@ public SubclassConstructorTest(Exception v)
value = v;
}
}

public class MultipleConstructorsTest
{
public string value;
public Type[] type;

public MultipleConstructorsTest()
{
value = "";
type = new Type[1] { null };
}

public MultipleConstructorsTest(string s, params Type[] tp)
{
value = s;
type = tp;
}
}
}
10 changes: 10 additions & 0 deletions src/testing/methodtest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -703,6 +703,16 @@ public static string DefaultParamsWithOverloading(int a = 5, int b = 6, int c =
{
return $"{a}{b}{c}{d}XXX";
}

public static string ParamsArrayOverloaded(int i = 1)
{
return "without params-array";
}

public static string ParamsArrayOverloaded(int i, params int[] paramsArray)
{
return "with params-array";
}
}


Expand Down
9 changes: 9 additions & 0 deletions src/tests/test_constructors.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,12 @@ class Sub(System.Exception):
instance = Sub()
ob = SubclassConstructorTest(instance)
assert isinstance(ob.value, System.Exception)


def test_multiple_constructor():
from Python.Test import MultipleConstructorsTest
import System

# Test parameterless
ob = MultipleConstructorsTest()
assert ob.value == ""
33 changes: 33 additions & 0 deletions src/tests/test_method.py
Original file line number Diff line number Diff line change
Expand Up @@ -1188,3 +1188,36 @@ def test_keyword_arg_method_resolution():
ob = MethodArityTest()
assert ob.Foo(1, b=2) == "Arity 2"

def test_params_array_overload():
res = MethodTest.ParamsArrayOverloaded()
assert res == "without params-array"

res = MethodTest.ParamsArrayOverloaded(1)
assert res == "without params-array"

res = MethodTest.ParamsArrayOverloaded(i=1)
assert res == "without params-array"

res = MethodTest.ParamsArrayOverloaded(1, 2)
assert res == "with params-array"

res = MethodTest.ParamsArrayOverloaded(1, 2, 3)
assert res == "with params-array"

res = MethodTest.ParamsArrayOverloaded(1, paramsArray=[])
assert res == "with params-array"

res = MethodTest.ParamsArrayOverloaded(1, i=1)
assert res == "with params-array"

res = MethodTest.ParamsArrayOverloaded(1, 2, 3, i=1)
assert res == "with params-array"

# These two cases are still incorrectly failing:

# res = MethodTest.ParamsArrayOverloaded(1, 2, i=1)
# assert res == "with params-array"

# res = MethodTest.ParamsArrayOverloaded(paramsArray=[], i=1)
# assert res == "with params-array"