diff --git a/CHANGELOG.md b/CHANGELOG.md index 387217c76..bc30155d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -52,6 +52,8 @@ One must now either use enum members (e.g. `MyEnum.Option`), or use enum constru - `PythonException.Restore` no longer clears `PythonException` instance. - Replaced the old `__import__` hook hack with a PEP302-style Meta Path Loader - BREAKING: Names of .NET types (e.g. `str(__class__)`) changed to better support generic types +- BREAKING: overload resolution will no longer prefer basic types. Instead, first matching overload will +be chosen. ### Fixed diff --git a/src/embed_tests/TestOperator.cs b/src/embed_tests/TestOperator.cs index 68a6e8e35..a5713274a 100644 --- a/src/embed_tests/TestOperator.cs +++ b/src/embed_tests/TestOperator.cs @@ -1,7 +1,9 @@ using NUnit.Framework; using Python.Runtime; +using Python.Runtime.Codecs; +using System; using System.Linq; using System.Reflection; @@ -212,21 +214,19 @@ public OperableObject(int num) return (a.Num >= b); } - public static bool operator >=(OperableObject a, PyObject b) + public static bool operator >=(OperableObject a, (int, int) b) { using (Py.GIL()) { - // Assuming b is a tuple, take the first element. - int bNum = b[0].As(); + int bNum = b.Item1; return a.Num >= bNum; } } - public static bool operator <=(OperableObject a, PyObject b) + public static bool operator <=(OperableObject a, (int, int) b) { using (Py.GIL()) { - // Assuming b is a tuple, take the first element. - int bNum = b[0].As(); + int bNum = b.Item1; return a.Num <= bNum; } } @@ -421,6 +421,7 @@ public void ForwardOperatorOverloads() [Test] public void TupleComparisonOperatorOverloads() { + TupleCodec.Register(); string name = string.Format("{0}.{1}", typeof(OperableObject).DeclaringType.Name, typeof(OperableObject).Name); diff --git a/src/runtime/methodbinder.cs b/src/runtime/methodbinder.cs index 1b7cc4736..e0600181b 100644 --- a/src/runtime/methodbinder.cs +++ b/src/runtime/methodbinder.cs @@ -433,9 +433,7 @@ internal Binding Bind(IntPtr inst, IntPtr args, IntPtr kw, MethodBase info, Meth pi = pi.Take(1).ToArray(); } int outs; - var margs = TryConvertArguments(pi, paramsArray, args, pynargs, kwargDict, defaultArgList, - needsResolution: _methods.Length > 1, // If there's more than one possible match. - outs: out outs); + var margs = TryConvertArguments(pi, paramsArray, args, pynargs, kwargDict, defaultArgList, outs: out outs); if (margs == null) { var mismatchCause = PythonException.FetchCurrent(); @@ -612,7 +610,6 @@ static object[] TryConvertArguments(ParameterInfo[] pi, bool paramsArray, IntPtr args, int pyArgCount, Dictionary kwargDict, ArrayList defaultArgList, - bool needsResolution, out int outs) { outs = 0; @@ -653,7 +650,7 @@ static object[] TryConvertArguments(ParameterInfo[] pi, bool paramsArray, } bool isOut; - if (!TryConvertArgument(op, parameter.ParameterType, needsResolution, out margs[paramIndex], out isOut)) + if (!TryConvertArgument(op, parameter.ParameterType, out margs[paramIndex], out isOut)) { return null; } @@ -681,16 +678,15 @@ static object[] TryConvertArguments(ParameterInfo[] pi, bool paramsArray, /// /// Pointer to the Python argument object. /// That parameter's managed type. - /// If true, there are multiple overloading methods that need resolution. /// Converted argument. /// Whether the CLR type is passed by reference. /// true on success - static bool TryConvertArgument(IntPtr op, Type parameterType, bool needsResolution, + static bool TryConvertArgument(IntPtr op, Type parameterType, out object arg, out bool isOut) { arg = null; isOut = false; - var clrtype = TryComputeClrArgumentType(parameterType, op, needsResolution: needsResolution); + var clrtype = TryComputeClrArgumentType(parameterType, op); if (clrtype == null) { return false; @@ -710,25 +706,14 @@ static bool TryConvertArgument(IntPtr op, Type parameterType, bool needsResoluti /// /// The parameter's managed type. /// Pointer to the Python argument object. - /// If true, there are multiple overloading methods that need resolution. /// null if conversion is not possible - static Type TryComputeClrArgumentType(Type parameterType, IntPtr argument, bool needsResolution) + static Type TryComputeClrArgumentType(Type parameterType, IntPtr argument) { // this logic below handles cases when multiple overloading methods // are ambiguous, hence comparison between Python and CLR types // is necessary Type clrtype = null; IntPtr pyoptype; - if (needsResolution) - { - // HACK: each overload should be weighted in some way instead - pyoptype = Runtime.PyObject_Type(argument); - if (pyoptype != IntPtr.Zero) - { - clrtype = Converter.GetTypeByAlias(pyoptype); - } - Runtime.XDecref(pyoptype); - } if (clrtype != null) { diff --git a/src/testing/conversiontest.cs b/src/testing/conversiontest.cs index 1f9d64e1b..7a00f139e 100644 --- a/src/testing/conversiontest.cs +++ b/src/testing/conversiontest.cs @@ -78,4 +78,17 @@ public override string ToString() return value; } } + + public class MethodResolutionInt + { + public IEnumerable MethodA(ulong address, int size) + { + return new byte[10]; + } + + public int MethodA(string dummy, ulong address, int size) + { + return 0; + } + } } diff --git a/tests/test_conversion.py b/tests/test_conversion.py index eec2bcde6..3322b836f 100644 --- a/tests/test_conversion.py +++ b/tests/test_conversion.py @@ -4,7 +4,7 @@ import pytest import System -from Python.Test import ConversionTest, UnicodeString +from Python.Test import ConversionTest, MethodResolutionInt, UnicodeString from Python.Runtime import PyObjectConversions from Python.Runtime.Codecs import RawProxyEncoder @@ -681,3 +681,15 @@ def CanEncode(self, clr_type): l = ob.ListField l.Add(42) assert ob.ListField.Count == 1 + +def test_int_param_resolution_required(): + """Test resolution of `int` parameters when resolution is needed""" + + mri = MethodResolutionInt() + data = list(mri.MethodA(0x1000, 10)) + assert len(data) == 10 + assert data[0] == 0 + + data = list(mri.MethodA(0x100000000, 10)) + assert len(data) == 10 + assert data[0] == 0