Skip to content

Commit 15ae386

Browse files
committed
Fix enums precedence in MethodBinder
1 parent 4172e3d commit 15ae386

File tree

2 files changed

+61
-5
lines changed

2 files changed

+61
-5
lines changed

src/embed_tests/TestMethodBinder.cs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ public void SetUp()
9595
CSharpModel.LastDelegateCalled = null;
9696
CSharpModel.LastFuncCalled = null;
9797
CSharpModel.MethodCalled = null;
98+
CSharpModel.ProvidedArgument = null;
9899
}
99100

100101
[Test]
@@ -1360,6 +1361,47 @@ def call_method_with_action3():
13601361
Assert.AreEqual(expectedInnerMethodCalled, CSharpModel.LastFuncCalled);
13611362
}
13621363

1364+
[Test]
1365+
public void NumericArgumentsTakePrecedenceOverEnums()
1366+
{
1367+
using var _ = Py.GIL();
1368+
1369+
var module = PyModule.FromString("NumericArgumentsTakePrecedenceOverEnums", @$"
1370+
from clr import AddReference
1371+
AddReference(""System"")
1372+
from Python.EmbeddingTest import *
1373+
from System import DayOfWeek
1374+
1375+
def call_method_with_int():
1376+
TestMethodBinder.CSharpModel().NumericalArgumentMethod(1)
1377+
1378+
def call_method_with_float():
1379+
TestMethodBinder.CSharpModel().NumericalArgumentMethod(0.1)
1380+
1381+
def call_method_with_numpy_float():
1382+
TestMethodBinder.CSharpModel().NumericalArgumentMethod(TestMethodBinder.Numpy.float64(0.1))
1383+
1384+
def call_method_with_enum():
1385+
TestMethodBinder.CSharpModel().NumericalArgumentMethod(DayOfWeek.MONDAY)
1386+
");
1387+
1388+
module.GetAttr("call_method_with_int").Invoke();
1389+
Assert.AreEqual(typeof(int), CSharpModel.ProvidedArgument.GetType());
1390+
Assert.AreEqual(1, CSharpModel.ProvidedArgument);
1391+
1392+
module.GetAttr("call_method_with_float").Invoke();
1393+
Assert.AreEqual(typeof(double), CSharpModel.ProvidedArgument.GetType());
1394+
Assert.AreEqual(0.1d, CSharpModel.ProvidedArgument);
1395+
1396+
module.GetAttr("call_method_with_numpy_float").Invoke();
1397+
Assert.AreEqual(typeof(decimal), CSharpModel.ProvidedArgument.GetType());
1398+
Assert.AreEqual(0.1m, CSharpModel.ProvidedArgument);
1399+
1400+
module.GetAttr("call_method_with_enum").Invoke();
1401+
Assert.AreEqual(typeof(DayOfWeek), CSharpModel.ProvidedArgument.GetType());
1402+
Assert.AreEqual(DayOfWeek.Monday, CSharpModel.ProvidedArgument);
1403+
}
1404+
13631405
// Used to test that we match this function with Py DateTime & Date Objects
13641406
public static int GetMonth(DateTime test)
13651407
{
@@ -1442,6 +1484,10 @@ public void NumericalArgumentMethod(decimal value)
14421484
{
14431485
ProvidedArgument = value;
14441486
}
1487+
public void NumericalArgumentMethod(DayOfWeek value)
1488+
{
1489+
ProvidedArgument = value;
1490+
}
14451491
public void EnumerableKeyValuePair(IEnumerable<KeyValuePair<string, decimal>> value)
14461492
{
14471493
ProvidedArgument = value;

src/runtime/MethodBinder.cs

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -389,14 +389,24 @@ internal static int ArgPrecedence(Type t, bool isOperatorMethod)
389389
return ArgPrecedence(Nullable.GetUnderlyingType(t), isOperatorMethod);
390390
}
391391

392+
// Enums precedence is higher tan PyObject but lower than numbers.
393+
// PyObject precedence is higher and objects.
394+
// Strings precedence is higher than objects.
395+
// So we have:
396+
// - String: 50
397+
// - Object: 40
398+
// - PyObject: 39
399+
// - Enum: 38
400+
// - Numbers: 2 -> 29
401+
392402
if (t.IsEnum)
393403
{
394-
return -2;
404+
return 38;
395405
}
396406

397407
if (t.IsAssignableFrom(typeof(PyObject)) && !isOperatorMethod)
398408
{
399-
return -1;
409+
return 39;
400410
}
401411

402412
if (t.IsArray)
@@ -414,7 +424,7 @@ internal static int ArgPrecedence(Type t, bool isOperatorMethod)
414424
switch (tc)
415425
{
416426
case TypeCode.Object:
417-
return 1;
427+
return 40;
418428

419429
// we place higher precision methods at the top
420430
case TypeCode.Decimal:
@@ -444,10 +454,10 @@ internal static int ArgPrecedence(Type t, bool isOperatorMethod)
444454
return 29;
445455

446456
case TypeCode.String:
447-
return 30;
457+
return 50;
448458

449459
case TypeCode.Boolean:
450-
return 40;
460+
return 60;
451461
}
452462

453463
return 2000;

0 commit comments

Comments
 (0)