Skip to content

Commit 8b4c6ea

Browse files
committed
Minor fixes
1 parent 97d47b7 commit 8b4c6ea

File tree

1 file changed

+37
-52
lines changed

1 file changed

+37
-52
lines changed

src/runtime/MethodBinder.cs

Lines changed: 37 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
using System.Collections;
33
using System.Collections.Generic;
44
using System.Linq;
5-
using System.Numerics;
65
using System.Reflection;
76
using System.Text;
87

@@ -320,18 +319,40 @@ internal List<MethodInformation> GetMethods()
320319
/// See: https://github.com/jythontools/jython/blob/master/src/org/python/core/ReflectedArgs.java#L192
321320
/// </remarks>
322321
private static int GetPrecedence(MethodInformation methodInformation)
322+
{
323+
return GetMatchedArgumentsPrecedence(methodInformation, null, null);
324+
}
325+
326+
/// <summary>
327+
/// Gets the precedence of a method's arguments, considering only those arguments that have been matched,
328+
/// that is, those that are not default values.
329+
/// </summary>
330+
private static int GetMatchedArgumentsPrecedence(MethodInformation methodInformation, int? matchedPositionalArgsCount, IEnumerable<string> matchedKwargsNames)
323331
{
324332
ParameterInfo[] pi = methodInformation.ParameterInfo;
325333
var mi = methodInformation.MethodBase;
326334
int val = mi.IsStatic ? 3000 : 0;
327-
int num = pi.Length;
328-
329335
var isOperatorMethod = OperatorMethod.IsOperatorMethod(methodInformation.MethodBase);
330336

331337
val += mi.IsGenericMethod ? 1 : 0;
332-
for (var i = 0; i < num; i++)
338+
339+
if (!matchedPositionalArgsCount.HasValue)
340+
{
341+
for (var i = 0; i < pi.Length; i++)
342+
{
343+
val += ArgPrecedence(pi[i].ParameterType, isOperatorMethod);
344+
}
345+
}
346+
else
333347
{
334-
val += ArgPrecedence(pi[i].ParameterType, isOperatorMethod);
348+
matchedKwargsNames ??= Array.Empty<string>();
349+
for (var i = 0; i < pi.Length; i++)
350+
{
351+
if (i < matchedPositionalArgsCount || matchedKwargsNames.Contains(methodInformation.ParameterNames[i]))
352+
{
353+
val += ArgPrecedence(pi[i].ParameterType, isOperatorMethod);
354+
}
355+
}
335356
}
336357

337358
var info = mi as MethodInfo;
@@ -351,32 +372,6 @@ private static int GetPrecedence(MethodInformation methodInformation)
351372
return val;
352373
}
353374

354-
/// <summary>
355-
/// Gets the precedence of a method's arguments, considering only those arguments that have been matched,
356-
/// that is, those that are not default values.
357-
/// </summary>
358-
private static int GetMatchedArgumentsPrecedence(MethodInformation method, int matchedPositionalArgsCount, IEnumerable<string> matchedKwargsNames)
359-
{
360-
var isOperatorMethod = OperatorMethod.IsOperatorMethod(method.MethodBase);
361-
var pi = method.ParameterInfo;
362-
var val = 0;
363-
for (var i = 0; i < pi.Length; i++)
364-
{
365-
if (i < matchedPositionalArgsCount || matchedKwargsNames.Contains(method.ParameterNames[i]))
366-
{
367-
val += ArgPrecedence(pi[i].ParameterType, isOperatorMethod);
368-
}
369-
}
370-
371-
var mi = method.MethodBase;
372-
var info = mi as MethodInfo;
373-
if (info != null)
374-
{
375-
val += ArgPrecedence(info.ReturnType, isOperatorMethod);
376-
}
377-
return val;
378-
}
379-
380375
/// <summary>
381376
/// Return a precedence value for a particular Type object.
382377
/// </summary>
@@ -390,7 +385,7 @@ internal static int ArgPrecedence(Type t, bool isOperatorMethod)
390385

391386
if (t.IsAssignableFrom(typeof(PyObject)) && !isOperatorMethod)
392387
{
393-
return -3000;
388+
return -1;
394389
}
395390

396391
if (t.IsArray)
@@ -746,26 +741,16 @@ internal Binding Bind(BorrowedReference inst, BorrowedReference args, BorrowedRe
746741
// We favor matches that do not use implicit conversion
747742
var matchesTouse = matches.Count > 0 ? matches : matchesUsingImplicitConversion;
748743

749-
// The best match would be the one with the most named arguments matched
750-
var maxKwargsMatched = matchesTouse.Max(x => x.KwargsMatched);
751-
// Don't materialize the enumerable, just enumerate twice if necessary to avoid creating a collection instance.
752-
var bestMatches = matchesTouse.Where(x => x.KwargsMatched == maxKwargsMatched);
753-
var bestMatchesCount = bestMatches.Count();
754-
755-
MatchedMethod bestMatch;
756-
// Multiple best matches, we can still resolve the ambiguity because
757-
// some method might take precedence if it received PyObject instances.
758-
// So let's get the best match by the precedence of the actual passed arguments,
759-
// without considering optional arguments without a passed value
760-
if (bestMatchesCount > 1)
761-
{
762-
bestMatch = bestMatches.MinBy(x => GetMatchedArgumentsPrecedence(methods.First(m => m.MethodBase == x.Method), pyArgCount,
763-
kwArgDict?.Keys ?? Enumerable.Empty<string>()));
764-
}
765-
else
766-
{
767-
bestMatch = bestMatches.First();
768-
}
744+
// The best match would be the one with the most named arguments matched.
745+
// But if multiple matches have the same max number of named arguments matched,
746+
// we solve the ambiguity by taking the one with the highest precedence but only
747+
// considering the actual arguments passed, ignoring the optional arguments for
748+
// which the default values were used
749+
var bestMatch = matchesTouse
750+
.GroupBy(x => x.KwargsMatched)
751+
.OrderByDescending(x => x.Key)
752+
.First()
753+
.MinBy(x => GetMatchedArgumentsPrecedence(methods.First(m => m.MethodBase == x.Method), pyArgCount, kwArgDict?.Keys));
769754

770755
var margs = bestMatch.ManagedArgs;
771756
var outs = bestMatch.Outs;

0 commit comments

Comments
 (0)