From 29fccdb78d38e1b4f9352dea99273c93f713a24a Mon Sep 17 00:00:00 2001 From: Daniel Abrahamsson Date: Wed, 30 Sep 2020 07:47:49 +0200 Subject: [PATCH] Select correct method to invoke when keyword arguments are used If there were two methods with the same name, but with different arity, `Foo(a)` and `Foo(a,b)`, and the latter was called with a keyword argument `some.Foo(0, b=1)`, `Foo(0)` would be called instead of `Foo(0,1)`. Fixes #1235. --- CHANGELOG.md | 1 + src/runtime/constructorbinder.cs | 2 +- src/runtime/methodbinder.cs | 2 +- src/testing/methodtest.cs | 6 ++++++ src/tests/test_method.py | 7 +++++++ 5 files changed, 16 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b0559c43c..0c48ecb90 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ details about the cause of the failure - Fix incorrect dereference in params array handling - Fix `object[]` parameters taking precedence when should not in overload resolution - Fixed a bug where all .NET class instances were considered Iterable +- Fix incorrect choice of method to invoke when using keyword arguments. ## [2.5.0][] - 2020-06-14 diff --git a/src/runtime/constructorbinder.cs b/src/runtime/constructorbinder.cs index 0f9806c0e..973707f02 100644 --- a/src/runtime/constructorbinder.cs +++ b/src/runtime/constructorbinder.cs @@ -89,7 +89,7 @@ internal object InvokeRaw(IntPtr inst, IntPtr args, IntPtr kw, MethodBase info) // any extra args are intended for the subclass' __init__. IntPtr eargs = Runtime.PyTuple_New(0); - binding = Bind(inst, eargs, kw); + binding = Bind(inst, eargs, IntPtr.Zero); Runtime.XDecref(eargs); if (binding == null) diff --git a/src/runtime/methodbinder.cs b/src/runtime/methodbinder.cs index 49bf5b171..df8579ca4 100644 --- a/src/runtime/methodbinder.cs +++ b/src/runtime/methodbinder.cs @@ -580,7 +580,7 @@ static bool MatchesArgumentCount(int positionalArgumentCount, ParameterInfo[] pa var match = false; paramsArray = parameters.Length > 0 ? Attribute.IsDefined(parameters[parameters.Length - 1], typeof(ParamArrayAttribute)) : false; - if (positionalArgumentCount == parameters.Length) + if (positionalArgumentCount == parameters.Length && kwargDict.Count == 0) { match = true; } diff --git a/src/testing/methodtest.cs b/src/testing/methodtest.cs index 9a4c408d6..30e42ac9f 100644 --- a/src/testing/methodtest.cs +++ b/src/testing/methodtest.cs @@ -699,6 +699,12 @@ public string PublicMethod(string echo) return echo; } } + + public class MethodArityTest + { + public string Foo(int a) { return "Arity 1"; } + public string Foo(int a, int b) { return "Arity 2"; } + } } namespace PlainOldNamespace diff --git a/src/tests/test_method.py b/src/tests/test_method.py index c9fc89c7c..a358025a5 100644 --- a/src/tests/test_method.py +++ b/src/tests/test_method.py @@ -1149,3 +1149,10 @@ def test_optional_and_default_params(): res = MethodTest.OptionalAndDefaultParams2(b=2, c=3) assert res == "0232" + +def test_keyword_arg_method_resolution(): + from Python.Test import MethodArityTest + + ob = MethodArityTest() + assert ob.Foo(1, b=2) == "Arity 2" +